1、编译

  前面介绍的,dofile是一个运行lua代码块的基本操作,实际上它是一个辅助函数。

loadfile才真正做了核心的工作。dofile(打开文件,执行里面的代码块)和loadfile(从文件或stdin中获取代码块)实际不运行代码,

只是编译,然后将结果作为一个函数返回。loadfile与dofile不同的 是它不会引发错误,只是返回错误值并不处理错误。

一般dofile定义:

function dofile(filename)
local f = assert(loadfile(filename)) --如果loadfile失败,assert就会引发一条错误
return f()
end

通常,如果我们要多次运行一个文件,只需用loadfile一次,再多次调用它的返回结果就可以了。

相对于dofile来说,它只编译一次,开销就小得多。

与loadfile类似的函数load,它是从字符串中读取代码,而不是文件。

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

f变成了一个函数,每次调用就执行"i = i + 1"

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

使用load的时候要小心,它的开销大,并且会返回一些难以理解的代码。

如果你想塑造一个便捷但粗糙的dostring(load and run a chunk):

load(s)()   -- 有语法错误,load返回nil就会报错

--优化的版本

assert(load(s))()

一般将load用于字面字符串是没有意义的:

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

--基本上等价于

f = function() i = i +  end

但是第二行要快的多,因为它只编译了一次,而第一行每次调用load都要重新编译。

因为load编译的时候不涉及词法域,所以两者还是有区别的:

i  =
local i =
g = load("i = i + 1 ; print(i)") -- 字符串,访问的是全局 i
f = function() i = i + ;print(i) end -- 函数块,访问的是local i
g() --> 33
f() --> 1

函数 f 访问的是local  i

函数 g 访问的是全局  i

因为load总是在全局环境去编译代码块。

load最典型的用处是执行外部代码,那些位于程序之外的代码( 就像加载配置文件config一样,之前疑惑的地方 )。

有很多地方需要用户自定义函数,就要求输入函数代码,然后调用load去求值。

如果要对一个表达式求值,则必须在其之前添加return,这样才能构成一条语句,返回表达式的值:

print"enter your expression:"        -- 输入 1 + 2
local r = io.read()
local func = assert(load("return " .. r))
print("the value is " .. func())       -- the value is 3

因为load返回的是函数,所有可以多次调用:

print "enter function to be plotted(with variable 'x'):"  --输入一个数字,因为string.rep(第二个参数要数字,如果输入a或者b之类的 返回值为nil)
local r = io.read()
local f = assert(load("return " .. r))
for i = , do
x = i
print(string.rep("*",f()))
end

loadfile的实质也是调用load,load接收一个"读取器函数--reader function",并在内部调用它来获取程序块:

它可以分几次返回一个程序块,load会反复调用它,直到返回nil。

下面的例子就等于loadfile:

f = load(io.lines(filename,"*L")) --每次调用io.lines,都返回一个函数

--下面的代码更高效

f = load(io.lines(filename,))

Lua把这些独立的代码块当作匿名函数的函数体。比如load(“a = 1”)等于:

function (...) a =  end

代码块也可以声明local变量:

f = load("local a = 10; print(a+20)")
f() --> 30

有了这些特点:可以重写上面的例子,避免用全局变量:

print "enter function to be plotted(with variable 'x'):"
local r = io.read()
local f = assert(load("local x = ...;return " .. r)) --把x声明为local变量,当调用f(i)时,...就变成了参数i。
for i = , do
print(string.rep("*",f(i)))
end

load不会引发错误,在错误情况中,load会返回nil及一条错误消息。

print (load("i i"))
--> nil [string "i i"]:1: syntax error near 'i'

此外,这些函数不会有其他副作用。

有一个误解,认为加载了一块代码,就定义了其中的函数。

在Lua中函数定义是一种赋值操作,也就是说,它们是在运行时才完成的操作:

一个foo.lua:

--file 'foo.lua'
function foo(x)
print(x)
end

运行它:

f = loadfile("foo.lua")

运行之后,foo函数只是编译,还没有被定义。为了定义它,必须运行这个chunk:

print(foo)        --> nil
f() -- defines 'foo',即运行它
foo("ok") --> ok

此外,若需要在一个商业品质的程序中执行外部代码,还要处理加载程序块时报告的错误。

如果代码是不可信的,还要在一个保护环境下执行。

chapter8_1 编译执行和错误的更多相关文章

  1. Step By Step(Lua编译执行与错误)

    Step By Step(Lua编译执行与错误) 1. 编译:    Lua中提供了dofile函数,它是一种内置的操作,用于运行Lua代码块.但实际上dofile只是一个辅助函数,loadfile才 ...

  2. C#编译执行过程

    前言 大家好,我是卫斯理(Wesley).喜欢武侠的朋友可能知道小说中也有个卫斯理,他是位冒险家,财力充沛,极富冒险精神,并且有着超强的好奇心,对奇异的事情总有"打破沙锅问到底"的 ...

  3. JAVA 文件编译执行与虚拟机(JVM)简单介绍

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytpo3 java程序的内存分配 JAVA 文件编译执行与虚拟机(JVM)介绍 ...

  4. 超具体Windows版本号编译执行React Native官方实例UIExplorer项目(多图慎入)

    ),React Native技术交流4群(458982758).请不要反复加群! 欢迎各位大牛,React Native技术爱好者加入交流!同一时候博客右側欢迎微信扫描关注订阅号,移动技术干货,精彩文 ...

  5. 前端必备:FastStoneCapture 和 Licecap &&& mingw c++ 编译执行

    端必备:FastStoneCapture 和 Licecap FastStoneCapture这个软件非常小,只有2M多,并且其功能很强大,包括截图,录制视频,量尺,取色等等,对于前端工程师绝对是必备 ...

  6. 编译 & 执行 C++ 程序

    编译 & 执行 C++ 程序接下来让我们看看如何把源代码保存在一个文件中,以及如何编译并运行它.下面是简单的步骤: 打开一个文本编辑器,添加上述代码.保存文件为 hello.cpp.打开命令提 ...

  7. TeamCity编译执行selenium上传窗口脚本缺陷

    2015-07-04 18:05 编写本文 TeamCity编译selenium脚本,对于上传窗口处理只支持sendKeys的使用,不支持模拟人为按下Enter键和使用autoIt等操作,即使本地调试 ...

  8. Java解释执行和编译执行

    以前有句话说:“Java是解释执行的 ” .现在看来确实不是很准确,至于原因,在此简略解释: 首先,我们先解释一下在Java中解释执行和编译执行的区别. 解释执行:将编译好的字节码一行一行地翻译为机器 ...

  9. JNI之——在cmd命令行下编译执行C/C++源文件

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/46604269 一直用java来敲代码,java配置好jre路径之后.在cmd下编译 ...

随机推荐

  1. Linux安装Firefly

    1.安装一些必要的东东 yum install -y gcc zlib zlib-devel lrzsz openssl openssl-devel python-devel mysql-devel ...

  2. php stdClass类的用法

    stdClass是PHP的一个基类,所有的类几乎都继承这个类,所以任何时候任何地方都可以被new,可以让这个变量成为一个object.同时,这个基类又有一个特殊的地方,就是没有方法.凡时用new st ...

  3. Linq 内联左联等

    我们在做SQL查询的时候经常会用到Inner Join,Left Join,笛卡尔积等等,连接方式的概念方面我想也不用给予太多解释, 我们今天的重点是让大家熟悉LINQ是如何使用Join来实现常用的表 ...

  4. 类型“System.Data.Objects.DataClasses.EntityObject”在未被引用的程序集中定义。

    说明: 在编译向该请求提供服务所需资源的过程中出现错误.请检查下列特定错误详细信息并适当地修改源代码. 编译器错误消息: CS0012: 类型“System.Data.Objects.DataClas ...

  5. 一个简单sql注入的poc

    最近在提高自己编程能力,拿一些实用的小工具练下.该脚本为python语言,主要涉及模块urllib,re. 功能:验证CmsEasy5.5爆账号密码 实验用源码:http://pan.baidu.co ...

  6. 面试题-Java基础-线程部分

    1.进程和线程的区别是什么? 进程是执行着的应用程序,而线程是进程内部的一个执行序列.一个进程可以有多个线程.线程又叫做轻量级进程. 2.创建线程有几种不同的方式?你喜欢哪一种?为什么? 有三种方式可 ...

  7. 关于 div随网页居中问题

    可以先在外部设置个 宽高 小于浏览器的 div 内容再根据 最外层 定位 这个代码是 左右居中的 <div style=" width:300px; height:300px; mar ...

  8. mac上设置sudo不要密码

    觉得每次sudo都需要设置密码太过麻烦,于是折腾了一番,谁知走了一番弯路记录下来. 以下是网上找到的步骤 chmod u+w /etc/sudoers  给当前用户增加写权限 vi /etc/sudo ...

  9. web.confgi转换,web发布时发布配置(debug/release)生成不同的配置文件

    在web.config下有两个config文件,分比为:web.debug.config和web.replease.config文件,打开之后可以看到demo,根据demo修改后即可在发布时根据选择的 ...

  10. 【Python之路】第四篇--Python基础之函数

    三元运算 三元运算(三目运算),是对简单的条件语句的缩写 # 书写格式 result = 值1 if 条件 else 值2 # 如果条件成立,那么将 “值1” 赋值给result变量,否则,将“值2” ...