假设我有一个文件名“test.lua”,其中包含以下行:
--[[ test.lua --]]
local f = function()
print"local function f in test.lua"
end
f_generate = function()
local fun = loadstring(" f()")
-- local env = getfenv(1)
-- set(fun,env)
return fun
end
f_generate()()
--[[ end of test.lua--]]
因为loadstring在全局环境下执行其操作,所以当我调用时 f_generate()() 我将收到一个错误“尝试调用全局'f'(零值)”
注释掉的代码表明功能环境无法解决这个问题。
因为table是lua中唯一的数据结构,(函数环境和其他很多东西都是通过表实现的),我认为假设闭包也是通过表实现是合理的,但我怎么能得到它呢?
答案 0 :(得分:4)
从提出的问题和提供的示例代码中,当函数和闭包是该语言中的第一类值时,我认为不需要使用loadstring()
。我会考虑这样做:
-- test.lua local f = function() print"local function f in test.lua" end f_generate = function() local fun = function() return f() end return fun end f_generate()() -- end of test.lua
如果f_generate有参数,那么动机会更清楚:
-- test.lua local f = function(y) print("local function f("..y..") in test.lua") end f_generate = function(name) local fun = function() return f(name) end return fun end f_generate("foo")() f_generate("bar")() -- end of test.lua
使用loadstring()
的解析器显式地将代码调用到loadstring()
的调用范围之外。局部变量不存储在任何环境表中。它们的实现方式与任何其他语言的实现方式大致相同:它们的存储由代码生成器分配,在编译之外无法访问。当然,调试模块(和API)能够查看它们,但绝不建议在调试器之外使用它。
保留对本地的引用以在范围之外使用的正确方法是作为闭包的真正upvalue。这就是fun = function() return f() end
所取得的成就。在这种情况下,值f
将保留为fun
中存储的函数的upvalue。请注意,在实践中,这种包装作为upvalue是非常有效的。查找值不需要名称查找,因为我使用了尾调用,所以也不需要额外的堆栈帧。
答案 1 :(得分:0)
我认为你混合了两件不同的东西:
闭包:为此,f()的定义应该在你想要包含的任何局部变量的范围内。
记住:范围是词汇,而环境是每个功能都认为是“全球空间”的。
由文本字符串构造的函数位于不同的词法空间中,就像它位于不同的文件中一样,因此它具有自己的范围,与其他函数分开。
顺便说一句,'debug'界面让你用一个函数的局部变量进行处理,所以可能有办法。我只是觉得不需要这样做。答案 2 :(得分:0)
您必须删除“本地”,否则将被垃圾收集。
--local f = function()
f = function()
print"local function f in test.lua"
end
答案 3 :(得分:0)
请参阅,您不能将函数/闭包视为表。请考虑以下代码:
local table = {
baz = {
blah = "bar"
},
foo = table.baz.blah
}
在这种情况下,您执行的操作相当于从更广泛的范围访问更窄范围内的内容。对于函数来说这是不可能的,这意味着如果这是真的,那么你可以访问通常不能的局部变量。
现在,修复你的代码:
local __cmp__table = {
[">"] = function(a,b) return a>b end,
[">="] = function(a,b) return a>=b end,
["<"] = function(a,b) return a<b end,
["<="] = function(a,b) return a<=b end,
["=="] = function(a,b) return a==b end,
["~="] = function(a,b) return a~=b end,
}
cmp = function(a, op, b)
return __cmp__table[op](a,b)
end
这将允许您使用适当的比较函数在任何两个变量上调用cmp。如果我错过了关于你的代码的观点,那么请告诉我!