lua 学习之编译

编译

  1. lua 是解释语言
  2. 但 lua 允许在运行源代码前,先将源代码编译为一种中间形式
  3. 区别解释语言的主要特征并不在于是否能编译它们
    1. 在于编译器是否是语言运行时库的一部分
    2. 是否有能力执行动态生成的代码

loadfile 函数

  1. dofile 函数是一种内置的操作,用于运行 lua 代码块

  2. dofile 仅是做了 loadfile的辅助工作

  3. loadfile 会从一个文件加载 lua 代码块

  4. 但不会运行代码,只是编译代码

  5. 然后将编译结果作为一个函数返回

  6. dofile 会引发错误

  7. loadfile 只会抛出错误值,但不处理错误

function dofile(filename)
    -- assert 返回错误值
    local f = assert(loadfile(filename))
    return f()
end
  1. 发生错误时,loadfile 会返回 nil 及错误消息,可自定义错误消息
  2. 在需要多次运行一个文件时,只需调用一次 loadfile ,多次调用它的返回结果,也就是那个函数即可
  3. dofile 开销则相比 loadfile大得多,因为 loadfile 只编译一次文件

loadstring 函数

  1. 从一个字符串中读取代码
  2. 同样会返回一个函数
  3. 开销很大,因为在每次调用 loadstring 时都会编译一次
  4. function 的写法只在编译对于程序块时被编译了一次
i = 0
f = loadstring("i = i + 1") -- 等效于 f = function() i = i + 1 end
f()
print(i) -- 1
f()
print(i) -- 2

-- dostring 完成加载并运行代码
assert(loadstring(s))() -- 语法错误 "attempt to call a nil value"
  1. loadstring 编译时不涉及词法域
  2. loadsting 只在全局环境中编译字符串,而非局部环境
i = 32
local i = 0
f = loadstring("i = i + 1; print(i)")
g = function() i = i + 1; print(i) end
f() -- 33 使用了全局变量
g() -- 1 使用了局部变量
  1. 可以执行外部代码
do
print("enter you expression:")
local l = io.read()
local func = assert(loadstring("return '" .. l .. "'"))
print("the value of your expression is " .. func())
end

do
print("enter function to be plotted(with variable 'x'):")
local l = io.read()
local f = assert(loadstring("return " .. l))
for i = 1, 20 do
    x = i
    print(x .. ":" .. string.rep("*", f()))
end
end
  1. loadfileloadstring ,有一个真正的原始函数 load

  2. loadfileloadstring 分别从文件和字符串中读取程序块

  3. load 接收一个「读取器函数」,并在内部调用它来获取程序块

  4. 读取器函数可以分几次返回一个程序块,load 会反复调用它,直到它返回 nil (表示程序块结束)为止

  5. 只有当程序块不在文件中,或者程序块过大而无法放入内存时,才会用到 load

  6. lua 将所有独立的程序块视为一个匿名函数的函数体,并且该匿名函数还具有可变长实参

  7. 与其他函数一样,程序块中可以声明局部变量

loadstring("a = 1") -- 等效于 function(...) a = 1 end
f = loadstring("local a = 10; print(a + 10)")
f() -- 20
  1. 重写读取输入示例,避免使用全局变量 x
print("enter function to be plotted (with variable 'x'):")
local l = io.read()
local f = assert(loadstring("local x = ...; return " .. l))
for i = 1, 20 do
    print(string.rep("*", f(i)))
end
  1. load 函数不会引发错误。在错误发生时,load 会返回 nil 以及一条错误信息
print(loadstring("a a"))
-- nil [string "a a":1 '=' expected nead 'a']

  1. loadfileloadstring 不会带来任何副作用
  2. 它们只是将程序块编译为一种中间表示,然后将结果作为一个匿名函数来返回。
  3. 而并不是加载了一个程序块,或定义了其中的函数
  4. 函数定义是一种赋值操作,是在运行时才完成的操作。
-- 编写一个 lua 文件,命名为 foo
function foo(x)
	print(x)
end

-- 在 cmd 中的 lua 解释器中输入
f = loadfile("你存放 foo 文件的路径")
print(foo()) -- nil
f() -- 定义函数
foo("test") -- test
  1. 执行外部代码的一些操作
  2. 处理加载程序块时报告任何错误
  3. 如果代码不受信任,需要在保护环境(即之前提到的「沙盒」中执行这些代码)
posted @ 2020-06-30 18:38  YYSd_jq  阅读(318)  评论(0编辑  收藏  举报