Ответ Луиса правильный, если можно надеяться на более краткий, чем новичок в языке. Я постараюсь уточнить это, надеюсь, не создавая дополнительной путаницы.
Ваш вопрос в контексте Lua, встроенного в конкретную модель калькулятора TI. Таким образом, некоторые детали будут отличаться от отдельных Lua, но в основном они будут касаться того, какие библиотеки и функции доступны в вашей среде. Это необычно (хотя Lua является открытым исходным кодом, возможно) для встроенных версий Lua значительно отличаться от автономной Lua, распространяемой его авторами. ( Lua Binaries - это хранилище двоичных файлов для многих платформ. Lua для Windows - полный комплект поставки Windows для батарей.)
Ваш пример кода имеет запутывающий фактор - детализацию, необходимую для взаимодействия с системой классов, предоставляемой средой калькулятора. Эта деталь в основном проявляется в отсутствии связи между вашим объектом equation
и вызываемой функцией equation:init()
. Так как есть методы, которые могут склеить это, это просто отвлечение.
Ваш вопрос, насколько я понимаю, сводится к путанице в том, как функции с переменным числом (функции с переменным числом аргументов) объявляются и реализуются в Lua. Из вашего комментария к ответу Луиса вы читали онлайн-издание «Программирование на Lua» (он же PiL). Вы цитировали раздел 5.2 . PiL - хороший источник информации о языке. К сожалению, переменные функции являются одной из особенностей, которая была в движении. Начиная с версии Lua 5.0, издание книги в сети правильно, но калькулятор TI, вероятно, работает на Lua 5.1.4.
В Lua 5 объявлена переменная функция со списком параметров, который заканчивается символом ...
, который обозначает остальные аргументы. В Lua 5.0 вызов был реализован с помощью «магической» локальной переменной с именем arg
, которая содержала таблицу, содержащую аргументы, соответствующие ...
. Для этого требовалось, чтобы каждая функция с переменными значениями при вызове создавала таблицу, что является источником ненужных накладных расходов и давления на сборщик мусора. Таким образом, в Lua 5.1 реализация была изменена: ...
может использоваться непосредственно в вызываемой функции в качестве псевдонима для совпадающих аргументов, но таблица фактически не создается. Вместо этого, если необходимо количество аргументов, вы пишете select("#",...)
, а если требуется значение n-го аргумента, вы пишете select(n,...)
.
Смешивающий фактор в вашем примере возвращается к системе классов. Вы хотите объявить функцию equation:init(...)
. Поскольку в этом объявлении используется синтаксис двоеточия, оно эквивалентно написанию equation.init(self,...)
. Таким образом, когда в конечном итоге вызывается через использование метаметода __call
в каркасе классов, первый действительный аргумент называется self
, и ноль или более фактических аргументов будет соответствовать ...
.
Как отмечено ниже в комментарии Амра, выражение select(n,...)
фактически возвращает все значения из n-го аргумента, что особенно полезно в этом случае для построения self.answers
, но также приводит к возможной ошибке при инициализации self.pipe
.
Вот мое пересмотренное приближение того, чего вы пытаетесь достичь в своем определении equation:init()
, но учтите, что у меня нет одного из калькуляторов TI под рукой, и это не проверено:
function equation:init(...)
self.equation = select(1, ...)
self.pipe = { (select(1,...)) }
self.selected = 1
self.answers = { select(2,...) }
end
В пересмотренной версии, показанной выше, я написал {(select(1,...))}
для создания таблицы, содержащей ровно один элемент, который является первым аргументом, и {select(2,...)}
для создания таблицы, содержащей все оставшиеся аргументы. Хотя существует ограничение на количество значений, которые могут быть вставлены в таблицу таким образом, этот предел связан с количеством возвращаемых значений функции или количеством параметров, которые могут быть переданы в функцию и поэтому не могут быть превышено ссылкой на ...
. Обратите внимание, что в общем случае это не так, и запись { unpack(t) }
может привести к тому, что не будет скопирована вся часть массива t
.
Несколько менее эффективным способом написания функции было бы написать цикл для переданных аргументов, что является версией в моем первоначальном ответе. Это будет выглядеть следующим образом:
function equation:init(...)
self.equation = select(1, ...)
self.pipe = {(select(1,...))}
self.selected = 1
-- Loop arguments to add answers.
local t = {}
for i = 2, select("#",...) do
t[#t+1] = select(i,...)
end
self.answers = t
end