Переменное количество аргументов функции Lua 5.1 - PullRequest
21 голосов
/ 27 сентября 2011

В моем скрипте Lua я пытаюсь создать функцию с переменным числом аргументов. Насколько я знаю, это должно работать, как показано ниже, но каким-то образом я получаю ошибку с Lua 5.1 на TI-NSpire (глобальный аргумент равен нулю). Что я делаю неправильно? Спасибо!

function equation:init(...)
    self.equation = arg[1]
    self.answers = {}
    self.pipe = {arg[1]}
    self.selected = 1

    -- Loop arguments to add answers.
    for i = 2, #arg do
        table.insert(self.answers, arg[i])
    end
end

instance = equation({"x^2+8=12", -4, 4})

Ответы [ 2 ]

36 голосов
/ 03 октября 2011

Ответ Луиса правильный, если можно надеяться на более краткий, чем новичок в языке. Я постараюсь уточнить это, надеюсь, не создавая дополнительной путаницы.

Ваш вопрос в контексте 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
24 голосов
/ 27 сентября 2011

Попробуйте

function equation:init(...)
     local arg={...}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...