我正在从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是本地的。
这可以修复吗?
答案 0 :(得分:13)
"loadstring does not compile with lexical scoping",所以不,它无法在loadstring
来电之外看到当地人。
这可以修复吗?
这取决于。为什么你首先使用loadtring? 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语法吗?
答案 1 :(得分:2)
无法以任何合理的方式完成。有关 why 的示例,请查看以下内容:
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
?它是否从加载函数的位置捕获变量,即使该函数不再存在?或者它是从它被调用的地方查找的?
第一个意味着函数在任何地方创建时都是词法范围的。能够在函数退出后访问变量意味着需要动态地将变量提升为upvalue,这不是Lua目前可以做的事情。就像现在一样,Lua可以在编译期间看到对局部变量的每次访问,因此它知道哪些变量变为upvalues(在性能命中时)以及哪些变量保持为本地变量。
第二个意味着loadstring
'd函数内的变量访问与Lua中的每个其他访问完全不同:Lua使用词法作用域,而不是动态作用域。这对Lua来说是一个巨大的实现变化,而且是一个非常不一致的变化。
所以,两者都不受支持。 可以控制动态加载函数的环境,使用Lua 5.1中的setfenv
或Lua 5.2中env
的{{1}}参数,但这些都不允许您可以自动访问本地变量。
答案 2 :(得分: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))