2

假设我有一个包含以下行的文件名“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'(一个 nil 值)”

注释掉的代码表明函数环境不能处理这个问题。

因为表是lua中唯一的数据结构,(函数环境和其他很多东西都是通过表实现的),我认为假设闭包也是通过表实现是合理的,但是我怎么能得到它呢?

4

4 回答 4

4

loadstring()从提出的问题和提供的示例代码来看,当函数和闭包是语言中的一等值时,我认为没有必要使用。我会考虑这样做:

--test.lua
局部 f = 函数()
  print"test.lua 中的局部函数 f"
结尾

f_generate = 函数()
  local fun = function() return f() end
  回归乐趣
结尾
f_generate()()
-- test.lua 结束

如果 f_generate 有一个参数,动机就更清楚了:

--test.lua
局部 f = 函数(y)
  print("本地函数 f("..y..") in test.lua")
结尾

f_generate = 函数(名称)
  local fun = function() return f(name) end
  回归乐趣
结尾
f_generate("foo")()
f_generate("bar")()
-- test.lua 结束

显式地通过解析器loadstring()将代码带到调用范围之外loadstring()。局部变量不存储在任何环境表中。它们的实现方式与使用任何其他语言的方式大致相同:它们的存储空间由代码生成器分配,并且在编译之外无法访问。当然,调试模块(和 API)可以窥视它们,但绝不建议在调试器之外使用。

保留对局部变量的引用以在范围外使用的正确方法是作为闭包的真正上值。这就是fun = function() return f() end. 在这种情况下,该值f将保留为存储在中的函数的上值fun。请注意,在实践中,这种包装为上值是非常有效的。无需名称查找即可找到该值,而且由于我使用了尾调用,因此也不需要额外的堆栈帧。

于 2009-05-22T20:56:05.220 回答
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。如果我错过了关于您的代码的要点,请告诉我!

于 2009-08-24T02:58:36.347 回答
0

我认为你混合了两种不同的东西:

  1. 闭包:为此, f() 的定义应该在您想要包含的任何局部变量的范围内。

    • 将局部变量插入动态编译的函数中。这不是 Lua 正式支持的。这不是环境问题,而是范围问题。

请记住:范围是词法的,而环境是每个函数认为的“全局空间”。

从文本字符串构造的函数位于不同的词法空间中,就像它位于不同的文件中一样,因此它有自己的范围,与其他函数分开。

顺便说一句,“调试”接口让你可以处理函数的局部变量,所以可能有办法。我只是觉得没有必要这样做。

于 2009-05-22T14:03:12.440 回答
0

您必须删除“本地”,否则它将被垃圾收集。

--local f = function()
f = function()
  print"local function f in test.lua"
end
于 2009-05-22T14:10:48.697 回答