可变参数函数 #
一、可变参数基础 #
1.1 基本语法 #
lua
-- 使用 ... 表示可变参数
local function sum(...)
local total = 0
for _, v in ipairs({...}) do
total = total + v
end
return total
end
print(sum(1, 2, 3, 4, 5)) -- 15
print(sum(10, 20)) -- 30
print(sum()) -- 0
1.2 固定参数与可变参数 #
lua
-- 固定参数在前,可变参数在后
local function format_string(separator, ...)
local parts = {...}
return table.concat(parts, separator)
end
print(format_string("-", "a", "b", "c")) -- a-b-c
print(format_string(", ", 1, 2, 3)) -- 1, 2, 3
1.3 访问可变参数 #
lua
-- 方式1:打包成表
local function print_args(...)
local args = {...}
for i, v in ipairs(args) do
print(i, v)
end
end
print_args("a", "b", "c")
-- 1 a
-- 2 b
-- 3 c
-- 方式2:直接遍历
local function print_args2(...)
for i = 1, select("#", ...) do
print(i, select(i, ...))
end
end
二、select 函数 #
2.1 select 基础 #
lua
-- select("#", ...) 返回参数数量
local function count_args(...)
return select("#", ...)
end
print(count_args(1, 2, 3)) -- 3
print(count_args()) -- 0
-- select(n, ...) 返回第 n 个参数及之后的所有参数
local function test_select(...)
print("从第2个开始:", select(2, ...))
print("从第3个开始:", select(3, ...))
end
test_select("a", "b", "c", "d")
-- 从第2个开始: b c d
-- 从第3个开始: c d
2.2 遍历可变参数 #
lua
-- 使用 select 遍历
local function sum(...)
local total = 0
for i = 1, select("#", ...) do
local v = select(i, ...)
total = total + v
end
return total
end
print(sum(1, 2, 3, 4, 5)) -- 15
-- 处理 nil 参数
local function print_all(...)
for i = 1, select("#", ...) do
local v = select(i, ...)
print(i, v)
end
end
print_all("a", nil, "c")
-- 1 a
-- 2 nil
-- 3 c
2.3 获取特定参数 #
lua
-- 获取第一个参数
local function first(...)
return ...
end
-- 获取最后一个参数
local function last(...)
return select(select("#", ...), ...)
end
print(first(1, 2, 3)) -- 1
print(last(1, 2, 3)) -- 3
-- 获取第 n 个参数
local function nth(n, ...)
return select(n, ...)
end
print(nth(2, "a", "b", "c")) -- b
三、参数打包与解包 #
3.1 打包参数 #
lua
-- 打包成表
local function pack(...)
return {...}
end
local args = pack(1, 2, 3, 4, 5)
print(args[1], args[3]) -- 1 3
-- 带计数的打包
local function pack_with_count(...)
return {
n = select("#", ...),
...
}
end
local result = pack_with_count(1, nil, 3)
print(result.n) -- 3
print(result[1]) -- 1
print(result[2]) -- nil
print(result[3]) -- 3
3.2 解包参数 #
lua
-- table.unpack 解包表
local arr = {1, 2, 3, 4, 5}
print(table.unpack(arr)) -- 1 2 3 4 5
-- 指定范围解包
print(table.unpack(arr, 2, 4)) -- 2 3 4
-- 解包作为函数参数
local function add(a, b, c)
return a + b + c
end
local nums = {1, 2, 3}
print(add(table.unpack(nums))) -- 6
3.3 转发参数 #
lua
-- 将参数转发给另一个函数
local function wrapper(func, ...)
print("调用前")
local result = func(...)
print("调用后")
return result
end
local function add(a, b)
return a + b
end
print(wrapper(add, 1, 2))
-- 调用前
-- 调用后
-- 3
四、实用示例 #
4.1 可变参数求值 #
lua
-- 求最大值
local function max(...)
local max_val = select(1, ...)
for i = 2, select("#", ...) do
local v = select(i, ...)
if v > max_val then
max_val = v
end
end
return max_val
end
print(max(3, 1, 4, 1, 5, 9, 2, 6)) -- 9
-- 求最小值
local function min(...)
local min_val = select(1, ...)
for i = 2, select("#", ...) do
local v = select(i, ...)
if v < min_val then
min_val = v
end
end
return min_val
end
print(min(3, 1, 4, 1, 5, 9, 2, 6)) -- 1
4.2 可变参数格式化 #
lua
-- 类似 printf 的函数
local function printf(format, ...)
io.write(string.format(format, ...))
end
printf("Hello, %s! You have %d messages.\n", "Lua", 5)
-- Hello, Lua! You have 5 messages.
-- 日志函数
local function log(level, ...)
local timestamp = os.date("%Y-%m-%d %H:%M:%S")
local message = string.format(...)
print(string.format("[%s] [%s] %s", timestamp, level, message))
end
log("INFO", "User %s logged in", "Alice")
log("ERROR", "Failed to open file: %s", "data.txt")
4.3 可变参数构建 #
lua
-- 创建数组
local function arr(...)
return {...}
end
local a = arr(1, 2, 3, 4, 5)
print(a[1], a[3]) -- 1 3
-- 创建字典
local function dict(...)
local result = {}
local args = {...}
for i = 1, #args, 2 do
result[args[i]] = args[i + 1]
end
return result
end
local d = dict("name", "Lua", "version", 5.4)
print(d.name, d.version) -- Lua 5.4
4.4 链式调用 #
lua
-- 链式操作
local Chain = {}
Chain.__index = Chain
function Chain.new(...)
return setmetatable({values = {...}}, Chain)
end
function Chain:map(func)
local result = {}
for i, v in ipairs(self.values) do
result[i] = func(v, i)
end
self.values = result
return self
end
function Chain:filter(func)
local result = {}
for _, v in ipairs(self.values) do
if func(v) then
table.insert(result, v)
end
end
self.values = result
return self
end
function Chain:reduce(func, initial)
local acc = initial
for _, v in ipairs(self.values) do
acc = func(acc, v)
end
return acc
end
function Chain:result()
return table.unpack(self.values)
end
-- 使用
local result = Chain.new(1, 2, 3, 4, 5)
:map(function(x) return x * 2 end)
:filter(function(x) return x > 4 end)
:reduce(function(acc, v) return (acc or 0) + v end)
print(result) -- 18 (6 + 8 + 10)
五、高级技巧 #
5.1 可变参数与命名参数 #
lua
-- 混合使用
local function create_element(tag, options, ...)
options = options or {}
local attrs = {}
for k, v in pairs(options) do
table.insert(attrs, string.format('%s="%s"', k, v))
end
local attr_str = #attrs > 0 and " " .. table.concat(attrs, " ") or ""
local content = table.concat({...})
return string.format("<%s%s>%s</%s>", tag, attr_str, content, tag)
end
print(create_element("div", {class = "container", id = "main"}, "Hello"))
-- <div class="container" id="main">Hello</div>
5.2 可变参数递归 #
lua
-- 递归处理可变参数
local function flatten(...)
local result = {}
local function process(...)
for i = 1, select("#", ...) do
local v = select(i, ...)
if type(v) == "table" then
process(table.unpack(v))
else
table.insert(result, v)
end
end
end
process(...)
return result
end
local flat = flatten(1, {2, 3}, 4, {5, {6, 7}})
print(table.concat(flat, ", ")) -- 1, 2, 3, 4, 5, 6, 7
5.3 可变参数缓存 #
lua
-- 缓存可变参数函数的结果
local function memoize_varargs(func)
local cache = {}
return function(...)
local key = table.concat({...}, "\0")
if cache[key] == nil then
cache[key] = {func(...)}
end
return table.unpack(cache[key])
end
end
local fib = memoize_varargs(function(n)
if n <= 1 then return n end
return fib(n - 1) + fib(n - 2)
end)
print(fib(50)) -- 快速计算
六、常见陷阱 #
6.1 nil 参数处理 #
lua
-- 问题:nil 参数会被忽略
local function bad_count(...)
return #{...}
end
print(bad_count(1, nil, 3)) -- 可能是 1 或 3
-- 解决:使用 select("#", ...)
local function good_count(...)
return select("#", ...)
end
print(good_count(1, nil, 3)) -- 3
6.2 尾部 nil #
lua
-- 问题:尾部 nil 丢失
local function process(...)
local args = {...}
for i = 1, #args do -- # 遇到 nil 会停止
print(i, args[i])
end
end
process(1, nil, 3, nil) -- 可能只打印 1
-- 解决:保存参数数量
local function process2(...)
local n = select("#", ...)
local args = {...}
for i = 1, n do
print(i, args[i])
end
end
6.3 性能考虑 #
lua
-- 避免重复打包
local function slow(...)
for i = 1, 1000 do
local args = {...} -- 每次都创建新表
process(args)
end
end
-- 推荐:打包一次
local function fast(...)
local args = {...}
local n = select("#", ...)
for i = 1, 1000 do
process(args, n)
end
end
七、总结 #
本章介绍了 Lua 的可变参数函数:
- 基本语法:使用
...表示可变参数 - select 函数:获取参数数量和特定参数
- 打包与解包:
{...}和table.unpack - 实用示例:求值、格式化、链式调用
- 高级技巧:递归处理、缓存
- 常见陷阱:nil 参数处理、尾部 nil
可变参数是 Lua 函数的重要特性。下一章,我们将学习表(Table)。
最后更新:2026-03-27