Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ruby-on-rails-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
修改Lua块环境:Lua 5.2_Lua - Fatal编程技术网

修改Lua块环境:Lua 5.2

修改Lua块环境:Lua 5.2,lua,Lua,我的理解是,在Lua5.2中,环境存储在名为\u ENV的upvalue中。这使得我在运行块之前,但在加载块之后,修改块的环境变得非常困惑 我想加载一个包含一些函数的文件,并使用块将这些函数注入到各种环境中。例如: chunk = loadfile( "file" ) -- Inject chunk's definitions chunk._ENV = someTable -- imaginary syntax chunk( ) chunk._ENV = someOtherTable chu

我的理解是,在Lua5.2中,环境存储在名为
\u ENV
的upvalue中。这使得我在运行块之前,但在加载块之后,修改块的环境变得非常困惑

我想加载一个包含一些函数的文件,并使用块将这些函数注入到各种环境中。例如:

chunk = loadfile( "file" )

-- Inject chunk's definitions
chunk._ENV = someTable -- imaginary syntax
chunk( )

chunk._ENV = someOtherTable
chunk( )
这在Lua内部是可能的吗?我能找到的修改这个upvalue的唯一例子是(另一个),但我正试图从Lua内部实现这一点。这可能吗

编辑:我不确定是否接受使用调试库的答案。测试结果表明,功能可能较慢。我这样做是为了提高效率,这样就不必为了将变量定义注入各种环境而从字符串(或文件,甚至更糟)解析整个块

编辑:看起来这是不可能的:

编辑:我想最好的方法是绑定一个可以修改环境的C函数。虽然这是一种更烦人的方式


编辑:我认为更自然的方法是将所有块加载到单独的环境中。通过设置引用块的全局副本的元表,任何其他环境都可以“继承”这些元素。这不需要在加载后进行任何upvalue修改,但仍然允许使用这些函数定义的多个环境。

我不明白为什么您希望避免使用调试库,而您却乐于使用C函数(在沙箱中两者都不可能)

可以使用debug.upvaluejoin
完成此操作:

function newEnvForChunk(chunk, index)
  local newEnv = {}
  local function source() return newEnv end
  debug.upvaluejoin(chunk, 1, source, 1)
  if index then setmetatable(newEnv, {__index=index}) end
  return newEnv
end
现在加载任何块,如下所示:

local myChunk = load "print(x)"
它最初将继承封闭的
\u ENV
。现在给它一个新的:

local newEnv = newEnvForChunk(myChunk, _ENV)
并为“x”插入一个值:

newEnv.x = 99
现在,当您运行区块时,它应该会看到
x
的值:

myChunk()

=>
99

允许块在不同环境中运行的最简单方法是将其显式化并使其接收环境。将此行添加到块的顶部可实现以下目的:

\u ENV=…

现在您可以随意调用
chunk(env1)
和以后的
chunk(env2)

在那里,没有带upvalue的
debug
magic


尽管您的区块是否包含该行很清楚,但您可以在加载时添加该行,方法是编写一个合适的读取器函数,首先发送该行,然后再发送文件的内容。

如果您不想修改区块(根据LHF的最佳答案),这里有两种选择:

设置空白环境,然后动态地将其环境更改为您的环境
函数编译(代码)
局部元={}
local env=setmetatable({},meta)
return{meta=meta,f=load('return'..code,nil,nil,env)}
结束
功能评估(模块、范围)
block.meta.\uu索引=范围
返回块.f()
结束
本地块=编译('a+b*c')
打印(eval(块,{a=1,b=2,c=3}))-->7
打印(eval(块,{a=2,b=3,c=4}))-->14
设置一个空白环境,每次都用自己的值重新设置它的值
函数编译(代码)
本地环境={}
return{env=env,f=load('return'..code,nil,nil,env)}
结束
功能评估(模块、范围)
对于k,成对(block.env)do block.env[k]=nil end
对于k,v成对(作用域)do block.env[k]=v end
返回块.f()
结束
本地块=编译('a+b*c')
打印(eval(块,{a=1,b=2,c=3}))-->7
打印(eval(块,{a=2,b=3,c=4}))-->14

请注意,如果微优化很重要,那么第一个选项大约是2✕ 与
\u ENV=…
答案一样慢,而第二个选项大约是8-9✕ 尽可能慢。

注意,在您插入的链接中,有一个我看到的评论,但我几乎不知道他的意思。我没有5.1的经验来理解@akaveluh,事实上我也不是100%确定,但从我的理解来看,实际上这意味着你似乎已经从其他人那里得到了一些东西:通过调试库或C API(事实上,调试确实使用C API)是可行的,尽管这在目的上有点困难和不明显,所以它不会在常规的日常Lua代码中被过度使用。来自lhf,答案具有很高的可信度,并且给出了关于原始意图的见解。哦,使用调试库真的可以吗?实际上,我并不是在测试环境中使用沙箱,而是在发布版本中使用沙箱。具体来说,我在一个游戏引擎中使用它,在这个引擎中,单独的环境充当基于聚合的模型中的组件。每个组件环境都应该有
Init
Update
Shutdown
的定义。理想情况下,每个“组件文件”中的所有局部变量都可以实例化到单独的环境中,这就是为什么我希望使用块注入到环境中。你认为有更好的方法吗,或者这是可以接受的?我还稍微编辑了我的问题,我说我不想接受调试库的答案。还可以使用
debug.setupvalue
?看起来这可能要简单得多。如果有帮助,我尝试了
debug.setupvalue
,效果非常好!我接受您的回答。@RandyGaul如果您有多个区块共享同一个
\u ENV
(默认设置),则
调试。setupvalue
将影响所有区块。如果创建独立的
\u ENV
s(使用
debug.upvaluejoin
),则它们不会相互影响。@RandyGaul重新调试函数开始缓慢:是的,但加载新块也是如此。这两种方法在启动时都只做一次。非常感谢你的回答。它看起来确实很不错,但是将这一行添加到文件中对于脚本编写来说是很糟糕的。因此,在读取文件之前插入这一行的评论真的很酷。我要去试试这个。