Categories

Tags

Table of Contents

  1. dofile 和 loadfile
  2. 结合_ENVload

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中语法有误时)

结合_ENVload

需求说明,对于任意判断条件,如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]