1) ... 是什么?
... 表示函数接收到的所有“额外参数”(可变参数列表)。
local function f(...)
print(...)
end
f(1, "a", true)
... 只能在可变参数函数里用(函数形参列表里写了 ...)
... 不是 table,它是一种“参数列表”
2) 最常见用法:原样转发参数
写包装函数/Hook 时非常常用:
local function wrap(fn, ...)
return fn(...)
end
比如你在 skynet 里写一个统一的日志/计时包装,基本都会用到“转发”。
3) 如何拿到第 1 个参数?(常用写法)
把前几个参数显式写出来,剩下的用 ...:
local function f(a, b, ...)
print("a", a, "b", b)
-- ... 是剩余参数
end
f(10, 20, 30, 40)
4) select:对 ... 做计数、取第 N 个
Lua 标准库里专门给可变参数用的。
4.1 统计参数个数
local function count(...)
return select("#", ...)
end
print(count()) -- 0
print(count(1,2,3,"x")) -- 4
4.2 取第 N 个参数
local function third(...)
return select(3, ...)
end
print(third("a","b","c","d")) -- c d(注意:返回第3个到最后所有参数)
如果你只想要“第 N 个单个值”,一般写:
local x = (select(3, ...))
用括号把多返回值“压成 1 个”。
5) 把 ... 变成 table:{...}(但要注意 nil)
local function pack_args(...)
local t = {...}
return t
end
关键点:nil 会丢失尾部长度信息
local t = {1, nil, 3}
print(#t) -- 不可靠(因为数组长度遇到 nil 行为不确定)
如果你要可靠保留 nil 和参数数量,用 table.pack:
local function pack(...)
return table.pack(...)
end
local t = pack(1, nil, 3)
print(t.n) -- 3
print(t[2]) -- nil 仍然保留
对应解包:
local function unpack_pack(t)
return table.unpack(t, 1, t.n)
end
6) 多返回值 + ... 的坑(必须掌握)
Lua 里函数可以返回多个值,.../return/赋值位置不同会影响“多返回值是否展开”。
6.1 在最后一个位置会“展开”
local function g() return 1,2,3 end
print(g()) -- 1 2 3
print((g())) -- 1 (括号会把多返回值压成1个)
6.2 return ... 会把所有参数原样返回
local function id(...)
return ...
end
print(id(1,2,3)) -- 1 2 3
6.3 把 ... 放进 {...} 会收集成 table(会展开成多个元素)
local function collect(...)
return {...}
end
7) 实战例子:日志函数(推荐你练)
local function log(fmt, ...)
print(string.format(fmt, ...))
end
log("x=%d y=%d", 10, 20)
如果你想支持“直接传任意对象”:
local function log_any(...)
local n = select("#", ...)
for i = 1, n do
local v = select(i, ...)
io.write(tostring(v), i == n and "\n" or "\t")
end
end