0Pricing
Lua Academy · 课时

可变参数和 ... 运算符

使用 ... 和 select() 处理长度可变的参数列表。

可变参数和 ... 运算符 是 CoddyKit 上的免费 Lua Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Lua Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Lua Academy 课程共包含 4 节课。

可变参数

Lua 函数可以在参数列表中使用 ...(三个点)来接收数量可变的参数。在函数内部,... 表示额外参数。您可以在表达式中使用它,将其传递给其他函数,或将其转换为表。

local function sum(...)
  local total = 0
  for _, v in ipairs({...}) do
    total = total + v
  end
  return total
end

print(sum(1, 2, 3))        -- 6
print(sum(10, 20, 30, 40)) -- 100

使用 select() 处理可变参数

select(n, ...) 会返回从第 n 个位置开始的所有参数。select("#", ...) 会返回参数总数,包括 nil 值。这比遇到第一个 nil 空缺就停止的 #{...} 更安全。

local function inspect(...)
  local n = select("#", ...)
  print("count:", n)
  for i = 1, n do
    print(i, select(i, ...))
  end
end

inspect("a", "b", nil, "d")
-- count: 4
-- 1  a
-- 2  b
-- 3  nil
-- 4  d

将 ... 传递给另一个函数

您可以使用 f(...) 将可变参数直接转发给另一个函数。当 ... 出现在调用的最后一个参数位置时,所有可变参数都会被传递。这对于包装函数或记录日志非常有用。

local function log(level, ...)
  io.write("[" .. level .. "] ")
  print(...)
end

log("INFO", "Server started on port", 8080)
log("ERROR", "File not found:", "config.lua")
-- [INFO] Server started on port  8080
-- [ERROR] File not found:  config.lua

table.pack 和 table.unpack

使用 table.pack(...) 可以将可变参数转换为表,同时将数量存储在字段 n 中。使用 table.unpack(t, i, j) 可以将表转换回可变参数。这两个函数结合使用,可以让您完全控制可变参数列表。

local function pack_and_show(...)
  local packed = table.pack(...)
  print("n =", packed.n)
  for i = 1, packed.n do
    print(i, packed[i])
  end
end

pack_and_show(10, nil, 30)
-- n = 3
-- 1  10
-- 2  nil
-- 3  30

固定参数与可变参数混用

一个函数可以同时包含固定参数和可变参数。固定参数位于前面;... 捕获其余参数。固定参数会先被赋值,然后剩余参数才会进入 ...。

local function printf(fmt, ...)
  io.write(string.format(fmt, ...))
end

printf("Hello, %s! You are %d years old.\n", "Alice", 30)
printf("Pi is approximately %.4f\n", math.pi)

local function firstAndRest(first, ...)
  print("first:", first)
  print("rest count:", select("#", ...))
end
firstAndRest(1, 2, 3, 4)

表构造器中的可变参数

您可以使用 {...} 将可变参数直接展开到表构造器中。当它用作最后一个元素时,所有参数都会被包含。不过,nil 空缺可能会导致 # 的结果不可靠——需要精确计数时,请优先使用 table.pack。

local function toArray(...)
  return {...}  -- collect all args as array
end

local arr = toArray("x", "y", "z")
for i, v in ipairs(arr) do
  print(i, v)
end
-- 1  x
-- 2  y
-- 3  z

可变参数表达式

... 可以出现在任何表达式位置。在多重赋值中,它会展开为所有值。在算术表达式中,只会使用第一个值。了解这一行为,可以避免将 ... 与其他表达式混用时出现隐蔽错误。

local function first(...)
  local x = ...
  return x
end

print(first(10, 20, 30))  -- 10  (only first)

local function addFirst(n, ...)
  local x = ...
  return n + x
end
print(addFirst(5, 3, 99)) -- 8  (3 is first ...)

print() 使用可变参数

Lua 内置的 print() 本身就是一个可变参数函数。它可以接收任意数量的参数,将每个参数转换为字符串,并用制表符分隔它们。了解这一点有助于您编写类似的实用函数。

-- print is vararg
print(1, 2, 3)           -- 1  2  3
print("a", nil, "b")     -- a  nil  b
print()                  -- (empty line)

-- Reimplementing a simple print-like function
local function myprint(...)
  local parts = {}
  for i = 1, select("#", ...) do
    parts[i] = tostring(select(i, ...))
  end
  io.write(table.concat(parts, "\t") .. "\n")
end
myprint(10, nil, 30)

使用 pcall 转发参数

将 pcall 与可变参数结合,可以创建通用的安全调用包装器。该包装器接收一个函数和任意数量的参数,通过 pcall 调用该函数,并返回结果或错误。

local function safeCall(fn, ...)
  local ok, result = pcall(fn, ...)
  if ok then
    return result
  else
    print("Error:", result)
    return nil
  end
end

local function divide(a, b)
  assert(b ~= 0, "division by zero")
  return a / b
end

print(safeCall(divide, 10, 2))   -- 5.0
print(safeCall(divide, 10, 0))  -- Error: ...

累积可变参数模式

一种常见的可变参数模式是遍历所有参数并累积结果。您可以使用局部表来完成,也可以通过 select 直接求和。两种方式都有效;对于参数较多的情况,使用表的方式更简洁。

local function average(...)
  local n = select("#", ...)
  if n == 0 then return 0 end
  local total = 0
  for i = 1, n do
    total = total + select(i, ...)
  end
  return total / n
end

print(average(10, 20, 30, 40))  -- 25.0
print(average(5))               -- 5.0

快速检查

select("#", 1, nil, 3) 会返回什么?

回顾:可变参数

总结:

  • function f(...) — 接受可变参数
  • select("#", ...) — 安全地计数,包括 nil 值
  • select(n, ...) — 返回从第 n 个位置开始的值
  • table.pack(...) — 将可变参数转换为带有 .n 计数的表
  • table.unpack(t) — 将表转换为可变参数
  • ... 位于最后一个位置时会完整展开;位于中间位置时只产生一个值

常见问题解答

「可变参数和 ... 运算符」课时是免费的吗?

是的 — 「可变参数和 ... 运算符」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Lua Academy 课程的其余内容,请升级到 CoddyKit PRO。 Lua Academy 课程共包含 4 节课。

「可变参数和 ... 运算符」这节课中我会学到什么?

使用 ... 和 select() 处理长度可变的参数列表。 你通过在浏览器中直接运行的动手代码来练习 Lua Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Lua Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Lua Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「可变参数和 ... 运算符」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Lua Academy 课中编写并运行代码吗?

能。每节 Lua Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 定义和调用函数
  2. 多个返回值
  3. 可变参数和 ... 运算符
  4. Lua 中的递归
← 返回 Lua Academy