我想为Lua实现bind()
,它在Javascript中广泛用于创建闭包。
下面的代码演示1参数案例:
function bind(func, arg1)
return function (...)
return func(arg1, ...)
end
end
local x = { data = 1 }
function x.print(self)
print self.data
end
outputX = bind(x.print, x)
outputX() -- print 1
我的问题是:如何支持任意数量的绑定参数?
答案 0 :(得分:4)
使用lua-vararg,您可以写:
local va = require "vararg"
function bind(f, ...)
local outer_args = va(...)
local function closure (...)
return f(va.concat(outer_args, va(...)));
end
return closure;
end
bind(print, 1, 2, 3)(4,5,6)
这是纯粹的lua实现
function packn(...)
return {n = select('#', ...), ...}
end
function unpackn(t)
return (table.unpack or unpack)(t, 1, t.n)
end
function mergen(...)
local res = {n=0}
for i = 1, select('#', ...) do
local t = select(i, ...)
for j = 1, t.n do
res.n = res.n + 1
res[res.n] = t[j]
end
end
return res
end
function bind(func, ...)
local args = packn(...)
return function (...)
return func(unpackn(mergen(args, packn(...))))
end
end
bind(print, 1, nil, 2, nil)(3, nil, 4, nil)
答案 1 :(得分:1)
由于Lua处理...
和多个返回值的方式,显而易见的方法不起作用:
function bind(func, ...)
local args = {...}
return function (...)
return func(unpack(args), ...)
end
end
失败,因为unpack
的多个返回值为adjusted down to 1 return value, due to the way it's used in the expression。
你可以这样做,这将以有限的方式工作:
function bind(func, ...)
local nargs = select("#", ...)
local args = {...}
return function (...)
local newArgs = {...}
local fullArgs = {}
copy(fullArgs, args)
copy(fullArgs, {...})
return func(unpack(fullArgs))
end
end
上面的copy
函数只是一个简单的实用函数,它将数组元素从一个表复制到另一个表。
这里的限制是,bind
调用和函子的任何参数都不允许nil
。如果是这样的话,那些论点以及其后的任何论点都将被剔除。
使用C API可以非常轻松地执行此操作。但是由于Lua语言的限制,使用正确的nil
处理非常困难。
答案 2 :(得分:1)
定义一个解包参数表的unpackN
函数:
function unpackN(argss, i)
i = i or 1
local iLocal = i
for _, args in ipairs(argss) do
local argsN = #args
if iLocal <= argsN then
return args[iLocal], unpackN(argss, i+1)
end
iLocal = iLocal-argsN
end
end
并按如下方式使用:
function bind(func, ...)
local A = {...}
return function (...)
local B = {...}
return func(unpackN {A, B} )
end
end
答案 3 :(得分:0)
尝试:
function bind(func, ...)
local rest = {...}
return function (...)
local args = {}
for i = 1, #rest do
args[i] = rest[i]
end
for i = 1, select("#", ...) do
table.insert(args, select(i, ...))
end
return func(unpack(args))
end
end
现在你有一个可变参数:
function add(...)
local sum = 0
for i = 1, select("#", ...) do
sum = sum + select(i, ...)
end
return sum
end
local add_2_3 = bind(add, 2, 3)
print(add_2_3(5))
希望有所帮助。