Тернарная операция
Ветераны, знакомые с C/C++, знают тернарную операцию a ? b : c. Использование этого синтаксиса для замены простых условных операторов позволяет сохранить код максимально кратким, не делая его при этом труднее для чтения.
int a, b, ret;
//if-else
if (a > b)
ret = a;
else
ret = b;
//三目运算符
ret = a > b ? a : b;
Тернарная операция в Lua
В нативной семантике Lua тернарная операция не реализована; обычно её имитируют с помощью логических операторов and и or.
В Lua и and, и or используют «сокращённое вычисление» (short-circuit evaluation), то есть вычисляют второй операнд только при необходимости. («Programming in Lua»)
local a, b, ret; ret = a > b and a or b
Перечислим все возможности:
Когда a > b:
a > b and a –> true a or b –> a
Когда a <= b:
a > b and a –> false a or b –> b
Отлично!
Подводные камни тернарного оператора в Lua
Следуя принципу перехода от частного к общему:
Общая форма тернарной операции a ? b : c
a = true, результат — b
a = false, результат — cСоответствует a and b or c в Lua
- b = true
- a = true
- a and b –> true
- b or c –> b
- a = false
- a and b –> false
- b or c –> c
- a = true
- b = false
- a = true
- a and b –> false
- b or c –> c
- a = false
- a and b –> false
- b or c –> c
- a = true
- b = true
Видно, что когда b = false, эмулируемое в Lua выражение a and b or c всегда возвращает c и не может восстановить исходное поведение тернарного оператора.
«Программирование на Lua» также рекомендует использовать if-else, чтобы избежать этой ситуации.
Обобщённый вариант a and b or c
Есть ли способ решить проблему, когда b = false не срабатывает?
Это напоминает мне распространённый экзаменационный вопрос по языку C: напишите макроопределение, возвращающее меньшее из двух значений.
Когда я впервые увидел эту задачу в школе, моей первой реакцией было:
#define MIN(A,B) A < B ? A : B
Однако такой способ записи не может возвращать правильные результаты во многих контекстах вложенного использования. Например: 2 * MIN(3, 4) раскрывается в 2 * 3 < 4 ? 3 : 4 = 6 < 4 ? 3 : 4, и результат равен 4.
Более «инженерный» стиль написания:
#define MIN(A,B) ((A) < (B) ? (A) : (B))
Любознательные читатели могут обратиться к: Правильный способ написания макроопределения, макроопределение тернарной операции
Из этого примера я начал задумываться: как убедиться, что b в a and b or c истинно, или что b не создаёт неоднозначности?
- У and приоритет оператора выше, чем у or; простое изменение порядка операций не помогает.
- Затем я вспомнил об универсальной таблице в Lua. Можно ли поместить все a, b и c в таблицы, чтобы изменить присутствие b? Заметьте, что {nil} также является объектом, который считается истинным.
Замените все a, b и c на таблицы: {a} and {b} or {c}. - В тернарной операции a — это условие, а результат — b или c. На самом деле a не нужно помещать в таблицу; иначе {a} всегда было бы истинным, что лишает смысла условие. А {b} или
результат {c} обязательно является таблицей, и эта таблица содержит только один элемент. Тогда к ней можно получить доступ через - Итак, более обобщённая тернарная операция в Lua выглядит так: (a and {b} or {c})
Итог
Признаюсь, чтобы узнать форму тернарной операции в Lua, достаточно просто поискать её и найти нужный ответ. Приведённый выше ход рассуждений несколько подозрителен: кажется, что ответ уже известен и к нему намеренно подводят. Однако я твёрдо убеждён, что при доказательстве задачи вывод — не самое главное; главное — процесс аргументации. В этой статье предпринята попытка восстановить вывод обобщённой тернарной операции в Lua, основываясь только на моём поверхностном понимании Lua. Если есть лучший ход рассуждений, мы можем обменяться мнениями.
Источник: https://blog.csdn.net/u010832643/article/details/77546887