Визначте значення за замовчуванням для аргументів функції


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 не працює, мені просто цікаво, чи це єдиний спосіб це зробити.

Відповіді:


86

Якщо вам потрібні іменовані аргументи та значення за замовчуванням, такі як 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таблиці в її метатаблиці (див . Документацію щодо метатаблиць ).

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

Як немовну функцію, такі дзвінки можна змінити, щоб забезпечити нову поведінку та семантику:

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

Деякі корисні функції для написання перекладачів аргументів: unpack(перехід до table.unpackпункту 5.2), setfenv(застарілий у 5.2 з новою _ENVконструкцією) та select(який повертає одне значення із заданого списку аргументів або довжину списку з '#').


Я тільки почав використовувати lua. Я буду робити це простим на час, але ваша публікація дуже інформативна. Можливо, стане в нагоді пізніше. Дякую.
ріпат

1
У більшості випадків простота - це шлях. Інтерфейси метапараметрів дійсно необхідні лише для об'єктів з великою кількістю необов'язкових атрибутів (наприклад, об'єктів інтерфейсу користувача).
Стюарт П. Бентлі,

Я думаю, що ця відповідь вирішує ті, хто вирішує питання, а не та, яка в даний час позначена як прийнята. Дякую за просвітлення :)
Скасувати

1
Слід зазначити, що 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

На мій погляд, немає іншого шляху. Це просто ментальність Луа: ніяких надмірностей, крім деяких синтаксичних цукрів, відсутність зайвих способів робити прості речі.


10
Цю відповідь повністю спростовує відповідь Стюарта П. Бентлі нижче, в якій функція викликається за допомогою конструктора таблиці. Це одна з сильних сторін Lua: хоча у неї немає купу чудових елементів, фундаментальні будівельні блоки Lua дозволяють робити безмежні речі, справді чудові невеликим розміром та простотою мови.
Колін Д Беннетт

@ColinDBennett Дякую, що висловилися: здається, ОП прочитало ваш коментар і того грудня відповідно змінило прийняту відповідь. (А тепер це "відповідь Стюарта П. Бентлі вище", для ясності: wink :)
Стюарт П. Бентлі

21

Технічно існує b = b == nil and 7 or b(що слід використовувати у випадку, коли falseє дійсним значенням, яке false or 7оцінюється як 7), але це, мабуть, не те, що ви шукаєте.


1
Якщо ви не перевіряєте наявність false, простіший спосіб - поставити змінну першим, а за замовчуванням останнім. b = b or 7
Ребс

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()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.