《lua程序设计》读书笔记 第8章:编译、执行与错误
尽管Lua是一种解释型语言,但是Lua确实允许在运行源代码前,先将源代码预编译为一种中间形式。其实,区分解释型语言的主要功能并不在鱼是否能编译它们,而是在于编译器是否是语言运行时库的一部分,即是否有能力(并且轻易的)执行动态生成的代码。可以说,正是因为存在诸如dofile装的函数,才可以将Lua称为一种解释型语言。
8.1 编译
8.1.1 loadfile
Lua中dofile函数用于运行Lua代码块,但实际上dofile只是一个辅助函数,loadfile才做了真正核心的工作。loadfile从一个文件中加载Lua代码块,但是它不会运行代码,而是编译代码,将编译结果作为一个函数返回。此外,loadfile不会引发错误,它只是返回错误值而不处理错误。
一般dofile如下定义:
function dofile(filename)
local f = assert(loadfile(filename))
return f()
end
如果loadfile失败,那么assert将引发一个错误。
8.1.2 loadstring
函数loadstring 与loadfile类似,不同之处在于它是从一个字符串中读取代码,而不是从文件中。
loadstring 是一个开销较大的函数,应该谨慎使用。如果代码中有错误,loadstring将返回nil。loadstring在每次调用时都将编译一次代码。loadsting在编译时不涉及词法域:
i=32
local i = 0
f = loadstring("i=i+1; print(i)")
g = function() i=i+1; print(i) end
f() -->3,使用了全局的i
g() -->1,使用了局部的i
loadstring最典型的用法是执行外部代码,loadstring的期望输入是一个程序块,也就是一系列语句。
8.2 C代码
与Lua代码不同的是,C代码需要在使用前先链接入一个应用程序,最简单的方式是动态链接机制。Lua为几种平台实现了一套动态链接机制。Lua提供的关于动态链接的功能都聚集在一个函数中,package.loadlib,该函数有两个字符串参数:动态链接的完整路径和一个函数名。
local path = "/user/local/lib/lua/5.1/socket.so"
local f = package.loadlib(path, "luaopen_socket")
loadlib是一个非常底层的函数。必须提供完整的库路径以及正确的函数名称。通常使用require来加载C程序库,这个函数会搜索指定的库,然后用loadlib来加载库,并返回初始化函数。
8.3 错误
Lua可以通过一个显式的error函数来引发一个错误,通常代码如下:
if not <condition> then error(<information>) end
与之等价的是asserth函数
assert(<condition>, <information>) -->第二个参数是可选的
8.4 错误异常与处理
如果需要在Lua中处理错误,则必须使用函数pcall来包装需要执行的代码。使用方法是通过pcall来调用可能引发错误的函数。
if pcall(foo) then
<常规代码>
else
<处理错误>
end
pcall函数以一种“保护模式”来调用它的第一个参数,其可以捕获函数执行种的任何错误,这样便可以在Lua中完成所有的异常处理了。
8.5 错误信息与追溯
error消息通常是一个描述了出错内容的字符串,其会附加一些关于错误发生未知的信息。
error函数还有第二个附加参数层level,用于指定调用层级中哪个层的函数来报告当前的错误,也就是说明水谁该为错误负责。
function foo(str)
if type(str) ~= "string" then
error("string expected", 2)
end
<常规代码》
end
另外debug库提供了两个通用的错误处理函数,一个是debug.debug,它会提供一个Lua提示符,让用户来检查错误的原因;另一个是debug.traceback,它会根据调用栈来构建一个扩展的错误消息,可以在任何时候调用这个函数来获取当前执行的堆栈信息。
此两个函数可以配合xpcall函数使用,xpcall比pcall多了一个参数–一个错误处理函数。当发生错误时,Lua会调用错误处理函数。
上一篇: lua中pairs和ipairs的区别
下一篇: Lua 脚本语言(上)