4

我正在从 Lua 中的字符串创建函数(x)。我正在使用的代码是

function fcreate(fs)
 return assert(loadstring("return function (x) return " .. fs.." end"))()
end

这适用于全局变量,例如

u=fcreate("math.sin(x)")

做正确的事。

但是,它似乎不喜欢局部变量。所以

local c=1
u=fcreate("math.sin(x)+c")

将不起作用,因为 c 是本地的。

这是可以修复的吗?

4

3 回答 3

13

"loadstring does not compile with lexical scoping",所以不,它看不到loadstring调用之外的本地人。


这是可以修复的吗?

那要看。你为什么首先使用 loadstring ?Lua 支持闭包作为第一类值,所以我无法从你的例子中看出为什么你需要loadstring。

你的例子:

u = fcreate("math.sin(x)+c")

无需loadstring或您的fcreate功能即可重写:

u = function(x) return math.sin(x)+c end

这当然与以下内容相同:

function u(x) return math.sin(x) + c end

我可以看到一个案例,loadstring如果您有想要编译成其他函数的用户可配置表达式,但您在本地c的案例表明情况并非如此。您是否正在尝试制作某种自制的 lamda 语法?

于 2012-07-08T04:31:04.090 回答
2

不能以任何合理的方式进行。有关原因的示例,请查看以下内容:

function makefunction(name)
    local a = 1
    local b = 2
    local c = 3
    -- ...
    return assert(loadstring("return " .. name))
end

local a = 4
local func = makefunction("a")
print(func())

如果这有效,打印什么?1还是4?它是否从加载函数的位置捕获变量,即使该函数不再存在?还是从它被调用的地方查找它?

第一个意味着该函数在其创建的任何地方都是词法范围的。在函数退出后能够访问变量意味着需要将变量动态提升为上值,这不是 Lua 目前可以做的事情。就像现在一样,Lua 可以在编译期间看到对局部变量的每次访问,因此它知道哪些变量要变成上值(在性能下降时)以及哪些要保留为局部变量。

第二个意味着loadstring'd 函数内部的变量访问与 Lua 中的所有其他访问完全不同:Lua 使用词法作用域,而不是动态作用域。这将是 Lua 中一个巨大的实现变化,而且是一个极其不一致的变化。

因此,两者都不支持。您可以控制动态加载函数的环境,setfenv在 Lua 5.1 中使用或在 Lua 5.2 中使用env参数load(...),但这些都不允许您自动访问局部变量。

于 2012-07-08T05:55:12.550 回答
1

如果您不需要改变局部变量,您可以做的是将这些值作为参数传递给生成的函数。您仍然需要手动指定要关闭的变量,但总比没有好。

例如,你可以建立你的闭包看起来像

return (function(a,b,c)
   return function(x) return print(a, x) end
end)(...)

我们可以通过改变你的功能来做到这一点

function fcreate(variables, fs)

  local varnames = {}
  local varvalues = {}
  local nvars = 0
  for n,v in pairs(variables) do
    nvars = nvars + 1
    table.insert(varnames, n)
    table.insert(varvalues, v)
  end

  local chunk_str = (
     'return (function(' .. table.concat(varnames, ',') .. ') ' ..
         'return function(x) return ' .. fs .. ' end ' ..
      'end)(...)'
  )

  return assert( loadstring(chunk_str) )( unpack(varvalues, 1, nvars) )

end

local a = 1;
local f = fcreate({a=a}, 'x+a')
print(f(1), f(2))
于 2012-07-10T20:09:08.213 回答