Lua基础 编译、运行、错误处理


尽管Lua是一门解析型的语言,但是在运行前也会被编译成某个中间状态。一门解析型的语言需要编译,这听起来有点不合常理。但是,实际上,解析型语言的与众不同,不是说它不需要编译,而是说它把编译作为其运行时的一部分,因此,它就可以执行各种来自外部的代码(例如网上的)。也许因为Lua中存在的如dofile 这样的函数,才使Lua可以被称为一门解析型语言。

1. 编译

之前我们介绍了dofile 来执行代码块,但是dofile 只是一个辅助函数。这里介绍一下loadfile 函数,它会从一个file中加载语句块,但是不运行;而是仅仅编译并作为一个函数返回。loadfile 不会像dofile 那样在运行时直接报错退出,而是返回错误码,这样我们就可以根据错误码做相应的处理。我们可以像下面这样定义dofile,这也可以看出dofile 和loadfile 的区别

function dofile (filename)
    local f = assert(loadfile(filename))
    return f()
end

注意,assert 可以使loadfile 发生错误时,报错退出。

dofile 在处理有些简单的任务时,使用起来比较方便,只需要一次调用,它会完成所有的操作(编译,运行啥的)。但是,loadfile更加灵活。发生错误的时候,loadfile 会返回nil + 'err_msg',我们可以根据实际情况对错误做出相应的处理。除此之外,如果想要运行一个file多次,可以先调用一次loadfile,然后调用loadfile 返回的结果多次,就可以了。这比调用几次dofile 开销要小很多,因为loadfile 只会执行一次编译,而dofile 每次都用都要编译。

loadstring 跟loadfile 差不多,区别是从一个string中加载代码块,而不是从file中。例如:

f = loadstring("i = i + 1")

f 是loadstring 的返回值,应该是function类型, 调用的时候,会执行i = i + 1 :

i = 0
f(); print(i) --> 1
f(); print(i) --> 2

loadstring 函数功能非常强大,但是运行起来,开销也不小,并且有时会导致产生一些莫名其妙的代码。因此,在用loadstring 之前,先考虑下有没有更简单的办法。
 
下面这行代码,不太好看,但是很方便。(不鼓励这种调用方法)

loadstring(s)()

如果有语法错误,loadstring 会返回nil + 类似‘attempt to call a nil value’这样的err_msg。如果想获取更详细的err_msg,那就需要用assert :

assert(loadstring(s))()

下面这样的使用方式(对一个字面值string使用loadstring),没什么意思,

f = loadstring("i = i + 1")

粗略的等价于:

但是,也不是完全相同,且继续往下看。第二种方式的代码运行起来更快,因为它只需要编译一次,而loadstring 每次都需要编译。下面我们来看看,上面两段代码到底有什么不同,如下示例:

i = 32
local i = 0
f = loadstring("i = i + 1; print(i)")
g = function () i = i + 1; print(i) end
f() --> 33
g() --> 1

g 函数处理的事局部变量i , 而f 函数处理的是全局变量i ,loadstring 总是在全局环境中进行编译。

loadstring 最典型的用途是:运行外来代码,例如网络上的,别人的。。。注意,loadsting 只能load语句,不能load表达式, 如果你想算一个表达式的值,那么前面要加上一个return 来返回给定表达式的值。下面是一个示例帮助理解:

print "enter your expression:"
local l = io.read()
local func = assert(loadstring("return " .. l))
print("the value of your expression is " .. func())

看一下运行情况:(注意第一个为什么报错了,想想什么才叫表达式)

loadstring 返回的就是一个普通的函数,可以多次调用:

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 -- global 'x' (to be visible from the chunk)
    print(string.rep("*", f()))
end

(string.rep 函数复制一个string给定的次数),下面是运行结果:

如果我们在深究一下,其实不管loadstring 也好,loadfile 也好,Lua中最基础的函数是load 。loadfile 从一个file中加载代码块,loadstring 从一个string中加载代码块,而load 调用一个reader函数来获取代码块,这个reader 函数分块返回代码块,load 调用它,直到它返回nil 。我们很少使用load 函数;通常只有在代码块不是位于一个file中,但是又太大了,不适合放到内存中(如果适合放到内存中,那就可以用loadstring 了)的时候,才会用load 。

  • 1
  • 2
  • 3
  • 4
  • 下一页

相关内容