Ответ 1
Ответ Луиса прав, если, к сожалению, может быть труднее, чем новичок. Я постараюсь немного разобраться в этом, надеюсь, не создавая дополнительной путаницы.
Ваш вопрос находится в контексте Lua, встроенного в определенную модель калькулятора TI. Таким образом, будут детали, которые отличаются от автономных Lua, но в основном эти детали будут касаться того, какие библиотеки и функции доступны в вашей среде. Это необычно (хотя, поскольку Lua является открытым исходным кодом, возможно) для встроенных версий Lua значительно отличается от автономного Lua, распространяемого его авторами. (Lua Binaries - это хранилище двоичных файлов для многих платформ. Lua для Windows - полный комплект поставки для Windows.)
В вашем примере кода есть сводящий фактор к деталям, которые ему необходимы для взаимодействия с системой классов, предоставляемой каркасом калькулятора. Эта деталь чаще всего выглядит как отсутствие связи между вашим объектом equation
и вызываемой функцией equation:init()
. Поскольку есть методы, которые могут склеить это, это просто отвлечение.
Ваш вопрос, как я понимаю, сводится к путанице в том, как переменные функции (функции с переменным числом аргументов) объявляются и реализуются в Lua. Из вашего комментария к Luis answer, вы читаете онлайн-версию программы Programming in Lua (aka 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
, а нулевые или более фактические аргументы будут соответствовать ...
.
Как отмечено в комментарии Amr ниже, выражение 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