lua-将带有参数的函数调用添加到堆栈中,然后稍后致电



我知道我可以将功能引用存储在表中,并用参数拨打,例如第一个答案中的第一个答案

中描述的参数

lua-执行存储在表中的函数

,但我需要为每个调用的表中存储参数。我该怎么做?

解释我想做什么。我想写一个转向行为课。如果您要计算转向力,则可以调用不同的功能(例如(目标(或追踪(目标((。

我希望能够"收集"所有函数调用并在末端执行它们(在表上循环并使用存储的参数执行每个函数(或取消所有内容。

可能吗?

另一个(可能更清洁的(替代方案:

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

如果已知可能的最大参数数,那么您可以在闭合时做一些简单的事情。

local function bind(f, p1, p2, p3, p4, p5)
  return function()
    return f(p1, p2, p3, p4, p5)
  end
end

值类型将在绑定后不可变,并且所有参数将通过(甚至是nils(。

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

如果要在表中存储一个函数和某些参数,然后用这些参数调用该函数,那么,您只需将参数与函数一起存储在表格中,然后将这些作为参数传递:

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

这就是我要做的:

-- pack one func + args into a table
function record( f, ... )
    return { func = f, n = select( '#', ... ), ... }
end
-- take a list/array/sequence of `record`ed functions & run them
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,则可以简化为…

-- pack one func + args into a table
function record( f, ... )
    return { func = f, ... }
end
-- take a list/array/sequence of `record`ed functions & run them
function run( list )
    for _, callinfo in ipairs( list ) do
        callinfo.func( table.unpack( callinfo ) )
    end
end

…但是我强烈建议建议只有在完成代码的其余部分并且您知道(mease!(时才执行此操作,这很慢。。(如果有一个错误将意外nil s引入参数列表中,则此版本将 alter参数列表 (通过删除元素(,而第一个将不变,无论是什么,是调试-Friendlier。(


如果您的空间确实很短,则可以通过不使用命名字段来节省一个值的空间

(附录:除LUA 5.2外,这似乎也比上面的其他两个变体要快一些 - 请参见下面的评论。(

-- (you can actually just do this inline)
function record( f, ... )  return { f, ... }  end
-- take a list/array/sequence of `record`ed functions & run them
function run( list )
    for _, callinfo in ipairs( list ) do
        callinfo[1]( table.unpack( callinfo, 2 ) )
    end
end

…但这取决于参数的数量,实际上可能浪费空间!(对于x86_64上的香草(puc-rio(lua,它将16个字节(1台电视(保存为0、1、3或7个参数,对2或6个参数无能为力,wastes 32字节为4、16 bytes for 4,和112个字节的8个参数(以及相同的两个模式不断增长/重复(。(

相关内容

最新更新