Определите значения по умолчанию для аргументов функции

86

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

function myfunction(a,b,c)
    b = b or 7
    c = c or 5
    print (a,b,c)
end

Это единственный способ? myfunction (a,b=7,c=5)Кажется, что стиль PHP не работает. Не то чтобы способ Lua не работал, мне просто интересно, единственный ли это способ сделать это.

рипат
источник

Ответы:

87

Если вам нужны именованные аргументы и значения по умолчанию, такие как PHP или Python, вы можете вызвать свою функцию с помощью конструктора таблицы:

myfunction{a,b=3,c=2}

(Это видно во многих местах Lua, например, в расширенных формах модулей протокола LuaSocket и конструкторов в IUPLua .)

Сама функция может иметь такую ​​подпись:

function myfunction(t)
    setmetatable(t,{__index={b=7, c=5}})
    local a, b, c =
      t[1] or t.a, 
      t[2] or t.b,
      t[3] or t.c
    -- function continues down here...
end

Любые значения, отсутствующие в таблице параметров, будут взяты из __indexтаблицы в ее метатаблице (см. Документацию по метатаблицам ).

Конечно, с помощью конструкторов таблиц и функций можно использовать более сложные стили параметров - вы можете писать все, что вам нужно. Например здесь функция, которая создает функцию, которая берет таблицы с именованными или позиционными аргументами из таблицы, определяющей имена параметров и значения по умолчанию, и функцию, принимающую обычный список аргументов.

Поскольку такие вызовы не связаны с языком, они могут быть изменены для обеспечения нового поведения и семантики:

  • Переменные могут принимать более одного имени
  • Позиционные переменные и ключевые слова могут чередоваться - и определение обоих может дать приоритет любому из них (или вызвать ошибку)
  • Можно использовать переменные без позиции только для ключевых слов, а также безымянные переменные только с позициями
  • Довольно подробное построение таблицы может быть выполнено путем анализа строки
  • Список аргументов можно использовать дословно, если функция вызывается не с одной таблицей.

Вот некоторые полезные функции для написания трансляторов аргументов unpack(переход к версии table.unpack5.2), setfenv(не рекомендуется в версии 5.2 с новой _ENVконструкцией) и select(которая возвращает одно значение из заданного списка аргументов или длину списка с '#').

Стюарт П. Бентли
источник
AI только начал использовать lua, пока буду проще, но ваш пост очень информативен. Может пригодиться позже. Спасибо.
ripat
1
В большинстве случаев простота - лучший способ. Интерфейсы с мета-параметрами действительно необходимы только для объектов с большим количеством необязательных атрибутов (таких как объекты пользовательского интерфейса).
Стюарт П. Бентли
Я думаю, что этот ответ решает вопросы, а не тот, который сейчас помечен как принятый. Спасибо за просветление :)
Отменить
2
Следует отметить , что x or defaultвыражение также используется в этом ответе на самом деле не истинный эквивалент параметров по умолчанию , но только упрощенный обходной путь , который работает только если оба nilи falseявляются недопустимыми значениями параметров. Скажем, значение по умолчанию для логического параметра x- trueи вызывающий передает явный false. Затем x or trueдает true, даже если falseбыло явно пропущено. Лучшая версия была бы if x == nil then x = default endболее читабельной; однако он по-прежнему не может обрабатывать явные nilаргументы.
Jesper
О, эй, теперь это принятый ответ! Ницца. (Для протокола и для того, чтобы поместить комментарий @Undo в контекст, ответ jpjacobs ниже был принятым ответом в течение очень долгого времени: я почти получил второй значок популистов поверх него.)
Стюарт П. Бентли
46

На мой взгляд, другого пути нет. Это просто менталитет Lua: никаких излишеств и, за исключением некоторого синтаксического сахара, никаких избыточных способов выполнения простых вещей.

jpjacobs
источник
10
Этот ответ полностью опровергается приведенным ниже ответом Стюарта П. Бентли, в котором функция вызывается с помощью конструктора таблицы. Это одна из сильных сторон Lua: хотя в нем нет множества излишеств, фундаментальные строительные блоки Lua позволяют делать неограниченное количество вещей, действительно замечательных благодаря небольшому размеру и простоте языка.
Colin D Bennett
@ColinDBennett Спасибо за сообщение: похоже, ОП прочитал ваш комментарий и в декабре того же года соответствующим образом изменил принятый ответ. (И теперь это «ответ Стюарта П. Бентли выше», для ясности: wink :)
Стюарт П. Бентли
21

Технически, есть b = b == nil and 7 or b(что следует использовать в случае, когда falseявляется допустимым значением, равным false or 77), но, вероятно, это не то, что вы ищете.

Стюарт П. Бентли
источник
1
Если вы не проверяете false, более простой способ - сначала поставить переменную, а последнюю - значение по умолчанию. b = b or 7
Rebs
2
Поскольку OP упомянул это в своем вопросе, я подумал, что было бы излишним упоминать (вопрос касался способов определения переменных по умолчанию, отличных от b = b or 7 ).
Стюарт П. Бентли
6

Единственный способ, который я нашел до сих пор, имеет смысл - это сделать что-то вроде этого:

function new(params)
  params = params or {}
  options = {
    name = "Object name"
  }

  for k,v in pairs(params) do options[k] = v end

  some_var = options.name
end

new({ name = "test" })
new()
NineBlindEyes
источник