Lua - 将具有参数的函数调用添加到堆栈中并以后调用它们
我知道我可以像在这里描述的那样,在表格中存储函数引用并带参数调用它们。但我需要为每次调用在表格中存储参数。我该怎么做?
为了解释我想干什么,我想写一个控制行为类。如果您正在计算控制力,您可以调用不同的函数,例如寻找(target)或追逐(target)。
我希望能够“收集”所有的函数调用并在结束时执行它们(遍历表并执行存储的每个函数与参数)或取消一切。
这是可能的吗?
另一种(可能更简洁)的替代方案:
function xxx(s1,s2,s3)
print(s1,s2,s3)
end
t = {}
t[#t+1] = { xxx, {'a','b','c'}}
t[#t+1] = { xxx, {'x','y','z'}}
for _,f in ipairs(t) do
f[1](table.unpack(f[2]))
end
下面是我的实现方式:
-- 把一个函数和参数打包成一个表
function record(f, ...)
return {func = f, n = select('#', ...), ...}
end
-- 执行一个经过记录的函数列表
function run(list)
for _, callinfo in ipairs(list) do
callinfo.func(table.unpack(callinfo, 1, callinfo.n))
end
end
使用示例:
-- 创建一个待执行的函数列表
todo = {}
todo[#todo+1] = record(print, "foo", "blah", nil, 23)
todo[#todo+1] = record(print, "baz")
-- 执行这个列表
run(todo)
--> foo blah nil 23
--> baz
还可以在 run 中使用 pcall,遇到错误不会中断执行;或者添加另一个函数,接受 (list, f, ...) 形式的参数,把调用信息打包进列表并附加到列表末尾。
如果可以保证参数列表中没有 nil,可以简化成以下形式:
-- 把一个函数和参数打包成一个表
function record(f, ...)
return {func = f, ...}
end
-- 执行一个经过记录的函数列表
function run(list)
for _, callinfo in ipairs(list) do
callinfo.func(table.unpack(callinfo))
end
end
不过我强烈建议只在最后面进行这种优化,确保其他代码都没有问题,并且经过测量发现这种方式确实慢。如果程序有 bug,会在参数列表中引入意外的 nil,导致这个版本修改了参数列表(删掉了一些元素),而前面那个版本则无论出现什么情况都不会修改参数列表,更加便于调试。
如果代码空间太小,可以使用以下方式节省一个值的空间。不过需要注意,这种方式会改变参数个数,所以可能会浪费空间。
( 附注: 除了 Lua 5.2,这种方式似乎比前面两种方式快一些,见下面的评论。)
--(你实际上可以就这样写)
function record(f, ...) return {f, ...} end
-- 执行一个经过记录的函数列表
function run(list)
for _, callinfo in ipairs(list) do
callinfo[1](table.unpack(callinfo, 2))
end
end
取决于参数个数的不同,这种方式可能会浪费空间,甚至比前面的方法更费空间。(对于 0、1、3 或 7 个参数,Vanilla(PUC-Rio)Lua 在 x86_64 上可以节省 16 个字节(1 个 TValue);对于 2 或 6 个参数则不会节省;对于 4 个参数则浪费 32 个字节,对于 5 个参数则浪费 16 个字节,对于 8 个参数则浪费 112 个字节(这个 2 的整数次幂模式会不断增长/重复)。)
如果知道可能的参数的最大数量,且很少,可以使用闭包进行简单的操作。
local function bind(f, p1, p2, p3, p4, p5)
return function()
return f(p1, p2, p3, p4, p5)
end
end
在绑定后,值类型将是不可变的,所有参数都将被传递(即使是 nil)。
local hello = bind(print, 'hello', 123)
hello() --> hello 123 nil nil nil
当然,您也可以绑定到引用类型。
local coords = { x=0, y=0 }
local t1 = bind(function(t, n) t.x = t.x + n end, coords, 20)
local t2 = bind(function(t, n) t.y = t.y + n end, coords, 50)
t1(); print('transform1', coords.x, coords.y) --> 20 0
t2(); print('transform2', coords.x, coords.y) --> 20 50
t1(); print('transform1', coords.x, coords.y) --> 40 50
而且,您仍然可以将所有内容存储在一个表中。
local t = {
bind(function(a, b) return 'add', a + b end, 5, 5),
bind(function(a, b) return 'sub', a - b end, 5, 5),
bind(function(a, b) return 'mul', a * b end, 5, 5),
bind(function(a, b) return 'div', a // b end, 5, 5),
}
for _, f in ipairs(t) do
print(f())
end
--> add 10
--> sub 0
--> mul 25
--> div 1
- Lua 虚拟机加密load(string.dump(function)) 后执行失败问题如何解决
- 我想创建一个 Nginx 规则,禁止访问
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?

如果你想在一个表中存储一个带有参数的函数,并在以后使用那些参数调用该函数,那么,你只需将参数与函数一起存储在表中,然后将它们作为参数传递:
functions_with_parameters = { { f = function (a, b) return a + b end, args = { 1, 2 } }, { f = function (a, b) return a - b end, args = { 100, 90 } } } for _, a in pairs(functions_with_parameters) do print(a.f(a.args[1], a.args[2])) end // 3 // 10