将字符串转换为Lua函数。

我正在Lua中从字符串创建函数(of 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是本地变量。

这可以解决吗?

点赞
用户501459
用户501459

"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局部变量,这表明这不是这种情况。你是要制作某种自定义lambda语法吗?

2012-07-08 04:31:04
用户5696
用户5696

无论如何都无法合理地完成。为了说明这一点,请看以下代码:

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?它是否可以捕捉到从已经不存在的函数所在地方中的变量?

如果打印出了1,那么这个函数是按词法作用域创建的。这意味着在函数退出后仍然可以访问变量,这就需要将变量动态提升为一个上值,这是 Lua 目前无法做到的。目前,Lua 在编译过程中可以看到每个对局部变量的访问,因此它知道将哪些变量转化为上值(会影响性能),哪些变量保留为本地变量。

如果打印出了4,那么在loadstring函数中的变量访问与 Lua 中的其他访问是完全不同的。Lua 使用的是词法作用域,而不是动态作用域。这将是 Lua 的一次巨大的实现变更,并且是极其不一致的。

因此,两种做法都不被支持。你可以使用setfenv(Lua 5.1)或 load(...)中的env参数(Lua 5.2) 控制动态加载函数的环境,但这两个方法都不能自动访问局部变量。

2012-07-08 05:55:12
用户90511
用户90511

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

例如,你可以构建一个闭包如下:

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-10 20:09:08