我想在Lua(5.3)中调用一个函数,修改环境以注入其他可用的函数,并这样做(a)无需修改函数本身的代码,以及(b)使用{{1} }调用该函数,能够捕获错误。
例如:
foo.lua (不允许修改pcall
的内容)
t:foo()
lib.lua (可以在此处进行任何更改以使其正常工作)
local t = require('lib')()
local b = 17
function t:foo()
local a = 42
print(a + b + c())
end
t()
我想修改以上内容,以在调用函数时将local lib = {}
function lib.c()
return 41
end
local function go(t)
for k,v in pairs(t) do
if 'function'==type(v) then print(pcall(v)) end
end
end
return function()
return setmetatable({}, {__call=go})
end
注入到函数的lib
链中,以便获得运行foo.lua的结果:
_ENV
而不是其当前输出:
100
true
我很确定我在5.1中完成了此工作(或等效的工作),但是false foo.lua:6: attempt to call a nil value (global 'c')
已经不存在了,我无法弄清楚如何为将要运行的现有功能修改环境,我无法修改其来源。 setfenv()
的功能似乎非常有限,但我假设我缺少有关如何使用它的知识。
答案 0 :(得分:1)
这对我有用。对您有用吗?
foo.lua
local L = require('lib')
local print=print
_ENV=L
local b = 17
function t:foo()
local a = 42
print(a + b + c())
end
t()
lib.lua
local lib = {}
function lib.c()
return 41
end
local function go(t)
for k,v in pairs(t) do
if 'function'==type(v) then print(pcall(v)) end
end
end
lib.t= setmetatable({}, {__call=go})
return lib
答案 1 :(得分:1)
通过this article来解决这个问题,它为getfenv
和setfenv
(依赖于debug
库)提供了纯Lua替换。
完整代码如下,但是解决方案大致是:
setmetable(lib, {__index=getfenv(function_to_call)})
setfenv(function_to_call, lib)
pcall(function_to_call)
require 'debug'
local function setfenv(fn, env)
local i = 1
while true do
local name = debug.getupvalue(fn, i)
if name == "_ENV" then
debug.upvaluejoin(fn, i, (function()
return env
end), 1)
break
elseif not name then
break
end
i = i + 1
end
return fn
end
local function getfenv(fn)
local i = 1
while true do
local name, val = debug.getupvalue(fn, i)
if name == "_ENV" then
return val
elseif not name then
break
end
i = i + 1
end
end
local lib = {}
function lib:c()
return 41
end
setmetatable(lib,{})
local function go(t)
for k,v in pairs(t) do
if 'function'==type(v) then
getmetatable(lib).__index=getfenv(v)
setfenv(v,lib)
print(pcall(v))
end
end
end
return function()
return setmetatable({}, {__call=go})
end