假设我有以下两个Lua文件:
在a.lua
:
local x = 5
f = dofile'b.lua'
f()
在b.lua
:
local fun = function()
print(x)
end
return fun
然后,如果我在shell中运行luajit a.lua
,则会打印nil
,因为在x
中定义的函数中无法看到b.lua
。预期打印应为5
。但是,如果我将所有内容放在一个文件中,那么它就是我想要的:
在aa.lua
:
local x = 5
local f = function()
print(x)
end
f()
运行luajit aa.lua
它会打印5
。
那么为什么在第一种情况下无法看到x
?
答案 0 :(得分:5)
顾名思义,局部变量是块的本地变量。
dofile()
从另一个文件加载块。因为它是另一个块,所以第一个块中的局部变量x
没有被它看到是有道理的。
答案 1 :(得分:3)
我同意这有点不直观,因为这不起作用。
你想说,在代码中的任何一点都有一组明确的“可见”变量 - 有些可能是本地的,有些可能是全局的,但是有一些解释器可以使用的地图解析任何一种名称。
当你使用dofile加载一个块时,它可以看到当前存在的任何全局变量,但显然它看不到任何局部变量。我们知道'dofile'不像C / C ++包含宏,它可以准确地给出你为局部变量描述的行为,但你仍然可以合理地期望它的这一部分可以起作用。
最终没有答案,但“那不是他们如何指定语言”。唯一满足答案可能是沿着'',否则会导致非显而易见的问题X'或'因为那时用例Y会变慢'。
我认为最好的答案是,如果所有名称在使用loadfile / dofile时根据它们的加载范围动态反弹,那么在将块编译为字节码时会抑制大量优化。在lua系统中,名称解析的工作方式类似于“在此范围内它是本地的,然后它绑定到该(已知)对象,或者,它是(唯一)全局表中的查找。”这个系统非常简单,只有少数几个选项,并没有很大的复杂空间。
我认为运行字节代码甚至不会跟踪局部变量的名称,它会在编译块后丢弃它们。如果他们想要像你建议的那样在块加载时允许动态名称解析,他们就必须撤消该优化。
如果您的问题不是为什么,而是我怎样才能使其正常工作,那么您可以采用的一种方法是在主机脚本中放置任何本地您希望在调用的脚本环境中可见的变量。执行此操作时,您需要将dofile拆分为几个调用。它与lua 5.1和lua 5.2略有不同。
在lua 5.1:
在a.lua
:
local shared = { x = 5 }
temp = loadfile('b.lua')
setfenv(temp, shared)
f = temp()
f()
在lua 5.2:
在a.lua
:
local shared = { x = 5 }
temp = loadfile('b.lua', 't', shared)
f = temp()
f()
答案 2 :(得分:1)
模块x
中定义的a.lua
变量无法在b.lua
中看到,因为它被声明为 local 。 local 变量的范围是它自己的模块。
如果您希望x
显示b.lua
,只需将其声明为全球即可。变量是 local 或 global 。要将变量声明为 global ,只需将其声明为 local 即可。
<强> a.lua 强>
x = 5
f = dofile'b.lua'
f()
<强> b.lua 强>
local fun = function()
print(x)
end
return fun
这样可行。
全局变量存在于全局命名空间中,可以通过_G
表在任何给定时间访问它。当Lua无法解决变量时,因为它没有在正在使用的模块内定义,所以Lua在全局命名空间中搜索该变量。总之,也可以将b.lua
写为:
local fun = function()
print(_G["x"])
end
return fun