Условный оператор и логика в Lua: специфика и реализация
Опубликовано:
Хотя Lua — лаконичный язык, логика в нем имеет ряд "подводных камней", которые необходимо учитывать выходцам из других языков программирования. Кратко:
- оператором проверки на неравенство является
~=; - всё истина, кроме
falseиnil; - условный оператор
if-elseif-elseоткрываетсяthenи закрываетсяend(ставится только в конце); switch-caseотсутствует, но переключатель можно реализовать с помощью таблиц;- тернарного оператора нет, но его можно эмулировать с помощью
andиor, так как они работают по принципу короткозамкнутых вычислений и возвращают один из своих операндов.
Синтаксис условного оператора в Lua
В Lua операторными скобками условного оператора (маркерами границ блока) являются ключевые слова then и end. Однако в отличие от Паскаля если условный оператор имеет несколько ветвей, end добавляется только после последней. В Lua имеется настоящее множественное ветвление. Однако в отличие от Python ключевым словом для дополнительных веток является elseif.
local score = io.read('n') if score >= 90 then print('Отлично') elseif score >= 75 then print('Хорошо') elseif score >= 50 then print('Сойдет') print('Но надо лучше') else print('Неудовлетворительно') end
Реализация конструкции выбора с помощью таблиц
В Lua нет оператора switch как в C++, или match как в Python. Однако подобие такого переключателя создают с помощью таблиц (хеш-карт), в которых ключами являются условия, а значениями — функции. Этот подход называют табличным ветвлением (table-driven approach). Он работает быстрее, чем длинная цепочка if-elseif, и код получается чище.
local actions = { move = function() print('Персонаж идет вперед...') end, jump = function() print('Персонаж подпрыгнул!') end, attack = function() print('Персонаж атакует мечом!') end } actions['jump']() -- Если нужна проверка local action = actions[io.read()] if action then action() else print('Неизвестная команда') end
Персонаж подпрыгнул! attack Персонаж атакует мечом!
Когда требуется просто вернуть значение в зависимости от ключа, а не выполнять код, функции не нужны:
local colors = { red = '#FF0000', green = '#00FF00', blue = '#0000FF' } local input = io.read() local hex = colors[input] or '#FFFFFF' print(hex)
green #00FF00
Особенности логических выражений и эмуляция тернарного оператора
В Lua логические выражения работают по принципу короткозамкнутых вычислений (short-circuit evaluation), то есть если результат определен, дальнейшие вычисления не производятся. Кроме этого, логические операторы and и or, как и в Python, возвращают не просто true/false, а сам объект (операнд), на котором завершилась проверка условия. Поэтому в предыдущем примере мы могли использовать выражение colors[input] or '#FFFFFF'.
Обратите внимание, оператор not всегда возвращает boolean-значение (true или false).
Классический тернарный оператор условие ? true_выражение : false_выражение эмулируется связкой (общепринятой идиомой):
условие and true_выражение or false_выражение
local balance = io.read('n') local status = (balance > 0) and 'В плюсе' or 'В минусе' print(status)
6 В плюсе
-4 В минусе
В примере когда условие истинно, то выражение true and 'В плюсе' возвращает второй операнд — в данном случае строку. Получается выражение 'В плюсе' or 'В минусе'. Поскольку первый операнд ложью не является, он и возвращается.
Если условие ложно, выражение false and 'В плюсе' возвращает первый операнд. Получается false or 'В минусе'. В таких случаях оператор or возвращает второй операнд.
Однако такая эмуляция тернарного оператора не подходит для случаев, когда код, который должен срабатывать при истинности условия, сам по себе возвращает false или nil. В этом случае тоже получается false or .... Пример такой логической ошибки:
local isAdmin = true -- Хотим для админа вернуть false local showAds = isAdmin and false or true print(showAds) -- выведет true, хотя планировалось false
Ложь только false и nil
Если бы в Python мы написали подобный код, как в примере ниже на Lua, то ожидали бы, что тела условных операторов не будут выполняться:
local a = '' if a then print('Hello, ' .. a) end local b = 0 if b then print(b + 10) end local c = {} if c then print('not empty') end
Однако в Lua пустая строка, ноль и пустая таблица — это истина.
Hello, 10 not empty
Ложью в Lua является только false и nil. Поэтому для примеров выше требуется более конкретизированная проверка значений:
local a = '' if a ~= '' then print('Hello, ' .. a) end local b = 0 if b ~= 0 then print(b + 10) end local c = {} if next(c) then print('not empty') end
В Lua оператором неравенства является ~= (комбинация знаков тильды и равно). Функция next возвращает первый ключ таблицы. Но если таблица пустая, она вернет nil.