高级用法
如基本示例中所述,你可以使用变量绑定参数和变量参数列表(...
)。你可以使用此事实递归拉出列表,就像在其他语言(如 Haskell)中一样。以下是利用这一点的 foldr()
的实现。每个递归调用将 vararg 列表的头部绑定到 x
,并将列表的其余部分传递给递归调用。这会破坏列表,直到只有一个参数(select('#', ...) == 0
)。之后,使用先前计算的结果将每个值应用于函数参数 f
。
function foldr(f, ...)
if select('#', ...) < 2 then return ... end
local function helper(x, ...)
if select('#', ...) == 0 then
return x
end
return f(x, helper(...))
end
return helper(...)
end
function sum(a, b)
return a + b
end
foldr(sum, 1, 2, 3, 4)
--> 10
你可以找到其他功能的定义是利用这种编程风格在这里通过问题#8 问题#3。
Lua 唯一惯用的数据结构就是表格。如果在序列中的任何位置存在 nil
s,则表长度运算符是未定义的。与表格不同,vararg 列表尊重明确的 nil
s,如基本示例和备注部分所述(如果你还没有,请阅读该部分)。由于工作量很小,vararg 列表可以执行除突变之外的每个操作。这使得 vararg 列表成为实现不可变元组的良好候选者。
function tuple(...)
-- packages a vararg list into an easily passable value
local co = coroutine.wrap(function(...)
coroutine.yield()
while true do
coroutine.yield(...)
end
end)
co(...)
return co
end
local t = tuple((function() return 1, 2, nil, 4, 5 end)())
print(t()) --> 1 2 nil 4 5 | easily unpack for multiple args
local a, b, d = t() --> a = 1, b = 2, c = nil | destructure the tuple
print((select(4, t()))) --> 4 | index the tuple
print(select('#', t())) --> 5 | find the tuple arity (nil respecting)
local function change_index(tpl, i, v)
-- sets a value at an index in a tuple (non-mutating)
local function helper(n, x, ...)
if select('#', ...) == 0 then
if n == i then
return v
else
return x
end
else
if n == i then
return v, helper(n+1, ...)
else
return x, helper(n+1, ...)
end
end
end
return tuple(helper(1, tpl()))
end
local n = change_index(t, 3, 3)
print(t()) --> 1 2 nil 4 5
print(n()) --> 1 2 3 4 5
上面和表之间的主要区别在于表是可变的并且具有指针语义,其中元组没有这些属性。另外,元组可以包含明确的 nil
并且具有从未未定义的长度操作。