Множественные возвраты и varargs

Изучаем две яркие особенности Lua: возврат нескольких значений и приём любого числа аргументов.

Множественный возврат — способность функции Lua вернуть сразу несколько значений, перечислив их через запятую после return.

В большинстве языков функция возвращает одно значение. Lua — приятное исключение: она умеет возвращать несколько и принимать сколько угодно аргументов.

Возврат нескольких значений

local function minmax(a, b)
  if a < b then
    return a, b   -- сначала меньшее, потом большее
  else
    return b, a
  end
end

local lo, hi = minmax(8, 3)
print("min:", lo, "max:", hi)

Вывод:

min:	3	max:	8

Множественный возврат повсюду в стандартной библиотеке: string.find возвращает начало и конец совпадения, pcall — успех и результат.

Лишние и недостающие значения

Если переменных меньше, чем возвращённых значений — лишние отбрасываются. Если больше — недостающие становятся nil:

local function three() return 1, 2, 3 end
local a = three()        -- берём только первое
local x, y, z, w = three()
print(a)
print(x, y, z, w)

Вывод:

1
1	2	3	nil

Переменное число аргументов (varargs)

Многоточие ... в параметрах означает «любое число аргументов»:

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

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

Вывод:

6
100

Внутри функции {...} собирает все аргументы в таблицу, по которой удобно пройтись циклом.

Функция select

Узнать число переданных аргументов помогает select("#", ...):

local function countArgs(...)
  return select("#", ...)
end
print(countArgs("a", "b", "c"))

Вывод:

3

Как работает под капотом

Множественные значения в Lua «разворачиваются» только в конце списка. Поэтому print(three(), 99) напечатает только 1 99: в середине списка от множественного возврата берётся лишь первое значение, а все три значения раскрылись бы только если вызов стоит последним.

Частые ошибки

  • Ставить вызов с множественным возвратом в середину списка аргументов — там останется лишь первое значение.
  • Использовать #{...} для подсчёта аргументов, когда среди них есть nil — лучше select("#", ...).
  • Забывать, что лишние возвращённые значения молча отбрасываются.

Итог

  • Функция Lua может вернуть несколько значений: return a, b, c.
  • Лишние значения отбрасываются, недостающие становятся nil.
  • Параметр ... принимает любое число аргументов; {...} собирает их в таблицу.
  • select("#", ...) возвращает точное число аргументов.
Проверьте себя
1. Сколько значений может вернуть функция в Lua?
AРовно одно
BНе больше двух
CНесколько, перечислив их через запятую после return
DТолько через таблицу
2. Что означает ... в списке параметров функции?
AНезавершённый код
BПриём любого числа аргументов (varargs)
CБесконечный цикл
DКомментарий