《lua程序设计》读书笔记 第8章:编译、执行与错误

来源:互联网 发布:淘宝网军用皮鞋女式 编辑:程序博客网 时间:2024/05/17 02:57

尽管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=32local i = 0f = loadstring("i=i+1; print(i)")g = function() i=i+1; print(i) endf()     -->3,使用了全局的ig()     -->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会调用错误处理函数。