Lua教程(六):编译执行与错误

1. 编译:
    Lua中提供了dofile函数,它是一种内置的操作,用于运行Lua代码块。但实际上dofile只是一个辅助函数,loadfile才是真正的核心函数。相比于dofile,loadfile只是从指定的文件中加载Lua代码块,然后编译这段代码块,如果有编译错误,就返回nil,同时给出错误信息,但是在编译成功后并不真正的执行这段代码块。因此,我们可以将dofile实现为:

代码如下:

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

这里如果loadfile执行失败,assert函数将直接引发一个错误。通过dofile的代码,我们还可以看出,如果打算多次运行一个文件中的Lua代码块,我们可以只执行loadfile一次,之后多次运行它返回的结果即可,这样就可以节省多次编译所带来的开销。这一点也是loadfile和dofile在性能上的区别。
    Lua中还提供了另外一种动态执行Lua代码的方式,即loadstring函数。顾名思义,相比于loadfile,loadstring的代码源来自于其参数中的字符串,如:
    f = loadstring("i = i + 1")
    此时f就变成了一个函数,每次调用时就执行"i = i + 1",如:

代码如下:

i = 0
 f() 
 print(i) --将输出1
 f()
 print(i) --将输出2

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返回的函数,如果需要对一个表达式求值,则必须在其之前添加return,这样才能构成一条语句,返回表达式的值,如:

代码如下:

i = 32
 f = loadstring("i = i + 1; return i * 2")
 print(f()) --输出66
 print(f()) --输出68。由于loadstring返回的就是正规的函数,因此可以被反复调用。

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)))
 end

 2. C代码:

上一小节介绍的是动态加载Lua代码,而事实上,Lua本身也支持动态加载C动态库中的代码,要完成该操作,我们需要借助于Lua内置的系统函数package.loadlib。该函数有两个字符串参数,分别是动态库的全文件名和该库包含的函数名称,典型的调用代码如下:
 

代码如下:

local path = "/usr/local/lib/test.so"
    local f = package.loadlib(path,"test_func")

由于loadlib是非常底层的函数,因为在调用时必须提供完整的路径名和函数名称。

    3. 错误:
    Lua作为一种嵌入式脚本语言,在发生错误时,不应该只是简单的退出或崩溃。相反,一旦有错误发生,Lua就应该结束当前程序块并返回到应用程序。
    在Lua中我们可以通过error()函数获取错误消息,如:
 

代码如下:

print "enter a number:"
    n = io.read("*number")
    if not n then error("invalid input") end

上面代码中的最后一行我们可以通过Lua提供的另外一个内置函数assert类辅助完成,如:
 

代码如下:

print "enter a number:"
    n = assert(io.read("*number"),"invalid input")

assert函数将检查其第一个参数是否为true,如果是,则简单的返回该参数,否则就引发一个错误。第二个参数是可选字符串。
    对于所有的编程语言而言,错误处理都是一个非常重要的环节。在实际的开发中,没有统一的指导原则,只能是在遇到问题后,经过缜密的分析在结合当时的应用场景,最后结合自己的经验再给出错误的具体处理方式。在有些情况下,我们可以直接返回错误码,而在另外一些情况下,则需要直接抛出错误,让开发者能够快速定位导致错误的代码源。

    4. 错误处理与异常:

Lua提供了错误处理函数pcall,该函数的第一个参数为需要“保护执行”的函数,如果该函数执行失败,pcall将返回false及错误信息,否则返回true和函数调用的返回值。见如下代码:
 

代码如下:

function foo()
    local a = 10
    print(a[2])
end

r, msg = pcall(foo)
if r then
    print("This is ok.")
else
    print("This is error.")
    print(msg)
end
--输出结果为:
--This is error.
--d:/test.lua:3: attempt to index local 'a' (a number value)

我们也可以给pcall函数直接传递匿名函数,如:

代码如下:

r, msg = pcall(function() error({code = 121}) end)
if r then
    print("This is ok.")
else
    print("This is error.")
    print(msg.code)
end
--输出结果为:
--This is error.
--121

 5. 错误消息与追溯:

通常在错误发生时,希望得到更多的调试信息,而不是只有发生错误的位置。至少等追溯到发生错误时和函数调用情况,显示一个完整的函数调用栈轨迹。要完成这一功能,我们需要使用Lua提供的另外一个内置函数xpcall。该函数除了接受一个需要被调用的函数之外,还接受第二个参数,即错误处理函数。当发生错误时,Lua会在调用栈展开前调用错误处理函数。这样,我们就可以在这个函数中使用debug库的debug.traceback函数,它会根据调用栈来构建一个扩展的错误消息。如:

代码如下:

function errorFunc()
    local a = 20
    print(a[10])
end

function errorHandle()
    print(debug.traceback())
end

if xpcall(errorFunc,errorHandle) then
    print("This is OK.")
else
    print("This is error.")
end

--输出结果为:
--[[stack traceback:
        d:/test.lua:7: in function <d:/test.lua:6>
        d:/test.lua:3: in function <d:/test.lua:1>
        [C]: in function 'xpcall'
        d:/test.lua:10: in main chunk
        [C]: ?
This is error.
--]]

(0)

相关推荐

  • Lua教程(六):编译执行与错误

    1. 编译:     Lua中提供了dofile函数,它是一种内置的操作,用于运行Lua代码块.但实际上dofile只是一个辅助函数,loadfile才是真正的核心函数.相比于dofile,loadfile只是从指定的文件中加载Lua代码块,然后编译这段代码块,如果有编译错误,就返回nil,同时给出错误信息,但是在编译成功后并不真正的执行这段代码块.因此,我们可以将dofile实现为: 复制代码 代码如下: function dofile(filename)      local f = ass

  • ASP.NET编译执行常见错误及解决方法汇总

    1.检测到有潜在危险的 Request.Form 值 原因: (1)在提交数据的页面或webconfig中没有对validateRequest的属性进行正确的设置 (2)HTML里面写了两个<form>引起 解决: 方案一: 在.aspx文件头中加入这句: <%@ Page validateRequest="false" %> 方案二: 修改web.config文件: <configuration> <system.web> <pa

  • Lua cjson模块编译笔记及错误解决方法

    使用文档:http://www.kyne.com.au/~mark/software/lua-cjson-manual.html 下载地址:http://www.kyne.com.au/%7Emark/software/download/lua-cjson-2.1.0.tar.gz 编译时可能会报错,要修改Makefile文件: 我下载的是lua jit版本,改了以下#部分内容 复制代码 代码如下: #LUA_INCLUDE_DIR =   $(PREFIX)/include LUA_INCLU

  • Lua中编译执行代码相关的函数详解

    可以说Lua之所以称为是一种解释型的语言,正是因为有诸如load这样的函数,因为这样的函数使得Lua可以执行动态生成的代码.下面具体来分析这些函数. load函数 load函数原型如下: 复制代码 代码如下: load (chunk [, chunkname [, mode [, env]]]) 该函数加载一个chunk,如果没有错误,则返回一个函数.如果传入chunk的值是一个字符串,则就加载这个字符串:如果传入chunk的值是一个函数,则这个函数必须返回一个字符串,并且load会一直调用这个

  • Lua教程(十七):C API简介

    Lua是一种嵌入式脚本语言,即Lua不是可以单独运行的程序,在实际应用中,主要存在两种应用形式.第一种形式是,C/C++作为主程序,调用Lua代码,此时可以将Lua看做"可扩展的语言",我们将这种应用称为"应用程序代码".第二种形式是Lua具有控制权,而C/C++代码则作为Lua的"库代码".在这两种形式中,都是通过Lua提供的C API完成两种语言之间的通信的. 1. 基础知识: C API是一组能使C/C++代码与Lua交互的函数.其中包括读

  • Go语言七篇入门教程六网络编程

    目录 1. Socket 编程 1.1 Dial()函数 2. HTTP 编程 2.1 HTTP 客户端 2.2 HTTP 服务端 2.2.1 处理 HTTP 请求 3. RPC 编程 3.1 Go 语言中的 RPC 支持与处理 3.2 Gob 简介 3.3 设计优雅的 RPC 接口 1. Socket 编程 在 Go 语言中编写网络程序时,我们将看不到传统的编码形式.以前我们使用 Socket 编程时,会按照如下步骤展开. 建立 Socket:使用 socket()函数. 绑定 Socket:

  • MyBatis学习教程(六)-调用存储过程

    一.提出需求 查询得到男性或女性的数量, 如果传入的是0就女性否则是男性 二.准备数据库表和存储过程 create table p_user( id int primary key auto_increment, name varchar(), sex char() ); insert into p_user(name,sex) values('A',"男"); insert into p_user(name,sex) values('B',"女"); insert

  • Lua教程(十九):C调用Lua

    1. 基础: Lua的一项重要用途就是作为一种配置语言.现在从一个简单的示例开始吧.   复制代码 代码如下: --这里是用Lua代码定义的窗口大小的配置信息     width = 200     height = 300 下面是读取配置信息的C/C++代码: 复制代码 代码如下: #include <stdio.h> #include <string.h> #include <lua.hpp> #include <lauxlib.h> #include

  • Lua教程(一):在C++中嵌入Lua脚本

    本系列教程主要介绍如何在C/C++程序里面嵌入Lua脚本,我打算从以下几个方面来介绍: 1.如何在C/C++里面嵌入Lua脚本 2.Lua访问C/C++数据结构(这里面要介绍类,结构体,函数,变量,枚举等数据类型在lua里面如何访问) 3.C/C++访问Lua的数据,主要是基本数据类型,函数和Table 4.Cocos2D-X里面的Lua绑定(含自动绑定与手动绑定) 5.Cocos2D-x里面Lua和C/C++相互调用 6.Cocos2D-x里面Lua和Java相互调用 7.Cocos2D-x里

  • cmake ios终端下执行提示错误 iOS version not found, tested: [5.0;5.1;6.0;6.1;7.0;8.3]的解决方案

    先给大家简单说下CMake. CMake是一个比make更高级的编译配置工具,它可以根据不同平台.不同的编译器,生成相应的Makefile或者vcproj项目. 通过编写CMakeLists.txt,可以控制生成的Makefile,从而控制编译过程. CMake自动生成的Makefile不仅可以通过make命令构建项目生成目标文件,还支持安装(make install).测试安装的程序是否能正确执行(make test,或者ctest).生成当前平台的安装包(make package).生成源码

随机推荐