您的位置:首页 > 编程语言 > Lua

Lua学习笔记10:编译

2020-06-05 05:18 393 查看

尽管将Lua称为一种解释性的语言,但Lua确实允许在运行源代码前将源代码预编译为一种中间形式。听上去编译似乎不在一种解释性语言的范畴之列,其实区别解释性语言的特征并不在于是否能编译它们,而在于编译器在运行时是否为库的一部分,即是否有能力且能轻易的执行动态生成的代码。正是因为Lua存在了类似dofile这样的函数,才可以将Lua称之为一种解释性的语言
一、Lua的dofile函数:dofile是一种Lua内置的操作,用于运行Lua的代码块, 会执行括号中文件路径的文件
例:dofile("E:/LuaTest/src/hellofile.lua")

二、loadfile函数:dofile只是一个辅助函数,loadfile才是真正的核心函数。相比于dofile,loadfile只是从指定的文件中加载Lua代码块,然后编译这段代码块,如果有编译错误,就返回nil,同时给出错误信息,但是在编译成功后并不真正的执行这段代码块。
例:
function dofile(filename)
     local f = assert(loadfile(filename))-->加载并编译该文件中的代码块,最后作为一个函数返回
     return f()
end
这里如果loadfile执行失败,assert函数将直接引发一个错误。通过dofile的代码,我们还可以看出,如果打算多次运行一个文件中的Lua代码块,我们可以只执行loadfile一次,之后多次运行它返回的结果即可,这样就可以节省多次编译所带来的开销。这一点也是loadfile和dofile在性能上的区别。

三、loadstring函数:一种动态执行Lua代码的方式。顾名思义,相比于loadfile,loadstring的代码源来自于其参数中的字符串。
例:
i=0
f = loadstring("i = i + 1")(该代码在每次调用到f这个函数时都会被编译一次) --等同于function() i=i+1 end(该代码只编译一次)  这两个代码编译时都没有涉及到词法域,所以并不等价
f()
print(i)  --i=1
f()
f()
print(i)  --i=3
此时f就变成了一个函数,每次调用时就执行"i = i + 1"。
若loadstring的字符串代码中有错误的话,loadstring就会返回一个nil
编译器就会返回一个“发生错误“attemp to call a nil value"”的信息
--------------------------------------------------------------------------
loadstring确实是一个功能强大的函数,但是由此而换来的性能开销也是我们不得不考虑的事情。所以对于很多常量字符串如果仍然使用loadstring方式,那就没有太大意义了,如上面的例子f = loadstring("i = i + 1"),因为我们完全可以通过f = function () i = i + 1 end的形式取而代之。而后者的执行效率要远远高于前者。毕竟后者只编译一次,而前者则在每次调用loadstring时均被编译。对于loadstring,我们还需要注意的是,该函数总是在全局环境中编译它的字符串,因此它将无法访问局部变量,而是只能访问全局变量.
例:
i = 32
 local i = 0
 f = loadstring("i = i + 1; print(i)")
 g = function() i = i + 1; print(i) end
 f()   --f函数中的i为全局变量i,因此输出33
g()   --g函数中的i为局部变量i,因此输出1
loadstring最典型的用处是可以执行外部代码,即位于程序之外的代码;如果需要让用户参与函数的定义时,就需要用户输入函数的代码,然后再用loadstring来对其求值。
由于loadstring的期望输入是一个程序块,即一系列的语句,如果需要对loadstring中的表达式求值的话,应该在其之前添加return,这样才能构成一条语句,返回表达式的值。
例:
i = 32
f = loadstring("i = i + 1; return i * 2")
print(f()) --输出66
print(f()) --输出68。由于loadstring返回的就是正规的函数,因此可以被反复调用。
-----------------------------------
do
l=io.read()
fun=assert(loadstring("return '"..l.."'"))-->如果输入的不是数字,应该用' '符号引用
print("asd"..fun())
end
------------------------------------
Lua将所有独立的程序块视为一个匿名函数的函数体,并且该匿名函数还具有可变长实参,因此在调用loadstring时,可以为其传递参数。
例:
local i = 30
--下面的...表示变长实参,将值赋给局部变量x。
local f = assert(loadstring("local x = ...; return (x + 10)    * 2")) 
for i = 1, 20 do
    print(string.rep("*",f(i)))-->string.rep函数可以重复的打印某个字符,有两个参数,第一个是要重复打印的字符,第二个是要重复打印的次数
end
------------------------------------
local l = io.read()

local f = assert(loadstring("return "..l)) 
for i = 1, 20 do
    print(string.rep("*",f()))
end

对于loadfile和loadstring函数,它们不会带来任何副作用,它们只是将程序块编译为一种中间表示,然后将结果作为一个匿名函数来返回
有一个会误解的地方是:加载了一个程序块等于定义了其中一个函数,这是错误的。在Lua中函数定义就是一种赋值操作,即在程序运行时才完成的操作。
使用一个函数前要对函数进行定义。
如果需要在一个商业品质的程序中执行外部代码的话,还应处理加载程序块时所报告的任何错误;若代码不可信任的话,还需要在一个保护环境中执行代码,以防止各种问题的产生

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: