Table of Contents
dofile 和 loadfile
dofile 从文件加载lua代码并执行,loadfile和dofile一样加载代码段,但不会运行该代码,只是编译代码,然后把编译完的代码段作为一个函数返回。可以把dofile 和loadfile看成下面的关系
function dofile()
local f = assert(loadfile(filename))
return f()
end
dofile在调用时就完成了所有工作(加载,编译,执行),因此比较方便。但是loadfile更加灵活,当我们需要多次运行同一个文件,那么只需要调用一次loadfile函数然后多次调用它的返回结果就好。由于只编译一次,因此开销比多次调用dofile小得多。
load 函数和loadfile类似,只不过它是从字符串中读取代码段,而不是文件中。如
f = load("i = i+1")
print(i) -- =>nil 因为f只是加载进来,并没有执行
i = 50 --声明全局变量
f()
print(i) -- =>51 ,此时i = 50, 执行后 i = i+1
f()
print(i) -- =>52,此时i = 51, 执行后 i = i+1
因此,如果要编写一个用后即弃的函数,可以这样写
load(s)()
assert(load(s)() -- 使用assert函数展示语法错误(当语法s中语法有误时)
结合_ENV
和load
需求说明,对于任意判断条件,如l.missionaryNum > m
,我想只是编辑一个条件判断语句,并且,可以轻松的替换变量 ,像 l = LocA ,m = 2
,从而达到 LocA.missionaryNum > 2
的效果。当这样的语句出现的地方很多时,就比较方便了,一次性搞定。相比去遍历字符串,替换字符串里的变量更加可靠。
--=========
--世界状态
--=========
WorldStates = {}
WorldStates.Objects = {
LocA = {
type = 'Location',
position = {x = 10,y = 0,z = 0},
missionaryNum = 3,
cannibalNum = 3
},
LocB = {
type = 'Location',
position = {x = -10,y = 0,z = 0},
missionaryNum = 0,
cannibalNum = 0
}
}
Tasks.Load = {
IsApplicable = function (l,m,c)
print("全局",_ENV)
print('全局',l,m,c)
load("print('全局',l,m,c)")()
local env = setmetatable({l = l,m = m,c = c},{__index = _G})
for k,v in pairs(WorldStates.Objects) do
env[k] = v
--print(k,env[k])
end
load("print('全局',l,m,c)")()
local _ENV = env
load("print('全局',_ENV)")()
print("局部",_ENV)
load("print('局部',_ENV)","chunk","bt",env)()
load("print('全局',l,m,c)")()
load("print('局部',l,m,c)","chunk","bt",env)()
load("l = _ENV['LocA']","chunk","bt",env)()
load("print(l)","chunk","bt",env)()
return load("return l.missionaryNum > m","chunk","bt",env)()
end
}
res = Tasks.Load.IsApplicable('LocA',2,0)
print(res)
load
函数有四个参数 ,分别是 chunk,chunkname,mode,env
- chunk 是表示代码块的字符串
- chunkname 用在错误消息和调试消息中,表示代码块的名字,默认为’chunk’
- mode 表示代码块是文本还是字符串
- b ,只能是二进制代码块
- t ,只能文本
- bt,既可以是二进制也可以是文本
- env,如果不提供,则默认使用全局环境
local env = setmetatable({},{__index = _G})
这一句是把旧环境装入新环境,继承旧环境
参考
- [Lua程序设计(第4版).22章(环境).page-252]