Условия и циклы

Что мы знаем на текущий момент?

  • Как объявлять переменные разных типов и размещать их в оперативной памяти
  • Как производить над ними различные вычисления
  • Как выводить результаты на консоль

Например, можем составить такую несложную программку:

local a = 6
print("'A' в квадрате равно: " .. a ^ 2)

Тут мы объявили переменную a, присвоили ей значение 6 (при этом интерпретатор Lua автоматически определил, что эта переменная имеет тип number).

Затем, мы вызвали команду для печати в консоль, а в скобках передали ей формулу (в программировании она называется "выражение").

Для того, чтобы знать, что печатать, интерпретатор должен вычислить это выражение.

Если взглянуть внимательно, то видно, что выражение состоит из трёх частей - строки, переменной и числа, которые разделены разными операторами.

Согласно таблице силы, самым сильным является оператор возведения в степень (^). Поэтому он вычисляется первым. Выражение принимает такой вид: "'A' в квадрате равно: " .. 36.0.

Остался всего один оператор - склеивания строк (.., он ещё называется "оператор конкатенации"). Число справа конвертируется в строку ("неявное преобразование") и склеивается со строкой слева.

Всё. На печать попадает строчка 'A' в квадрате равно: 36.0.

Условия

В программке выше у нас всё линейно. Сначала одна команда, потом другая команда.

А что, если нам надо выполнять часть команд не всегда, а только при определённых условиях?

Для этого в Lua есть специальное ключевое слово: if.

Работает оно так:

local a = 6

if a < 10 then
  print("Число A меньше десяти!")
else
  print("Число A больше или равно 10!")
end

Несложно догадаться, что программа напечатает в консоль строку "Число A меньше десяти!".

Как она это сделает?

Команда if имеет такую структуру:

if <логическое выражение> then
  <код, который выполнится, если выражение равно true>
else
  <код, который выполнится, если выражение равно false>
end

Логическое выражение - это любое выражение, результат которого будет либо true, либо false. Например: a < 5, true or false, a == nil или даже a == 6 and b ~= 10.

То есть, когда интерпретатор дойдёт до условия, первое что он сделает - это вычислит, чему равно логическое выражение. А дальше, в зависимости от результата, станет выполнять либо первую "ветку" кода, либо вторую.

Обратите внимание, что обе ветки кода имеют отступ в 2 пробела слева. Это важное правило "красивого кода".

Поверьте, читать сложный код, в котором не соблюдаются отступы - мучение.

Условие с одной веткой

Ветка else на самом деле не обязательна. Можно использовать сокращённую версию, которая будет выполняться только тогда, когда выражение равно true.

local x = true
if x then print("Yay!") end

Как видите, если код внутри "ветки" не слишком длинный, можно пойти ещё дальше, и написать всё условие в одну строку.

Условие с несколькими ветками

Бывают и обратные случаи. Когда нам надо проверить несколько случаев. Можно просто написать несколько условий:

local a = 3
if a == 1 then print("Число равно 1") end
if a == 2 then print("Число равно 2") end
if a == 3 then print("Число равно 3") end

А можно соединить их вместе:

local a = 3
if a == 1 then print("Число равно 1")
elseif a == 2 then print("Число равно 2")
else then print("Число равно 3") end

Какой в этом плюс? Иногда это просто выглядит красивее. Кроме того, если "сработает" какая-то одна ветка, интерпретатор не будет проверять другие и продолжит выполнять программу со следующей команды после условия.

В первом варианте (с отдельными условиями), интерпретатору пришлось бы проверить все ветки. Это полезно только если какие-то условия могут выполниться одновременно.

Циклы

Второй интересный случай - это когда нам надо выполнить один и тот же код несколько раз.

Например мы хотим напечатать 5 приветствий.

print("Hello!")
print("Hello!")
print("Hello!")
print("Hello!")
print("Hello!")

В принципе сойдёт. Но... А что если нам надо 100 приветствий? Программа грозит стать длинноватой.

Китайских программистов такие мелочи не останавливают, но мы-то не китайские программисты.

Для того чтобы повторять одни и те же команды раз за разом, в Луа есть ключевые слова for и while. Это - операторы цикла.

Цикл - это кусок кода, который будет выполняться несколько раз подряд, согласно какому-то условию. Процесс выполнения цикла называется итерацией.

Цикл for

У этого цикла есть два применения. Первое - выполнить код X раз. Второе - прошерстить все ключи в таблице.

Таблицы мы не изучали пока, поэтому сосредоточимся на первом.

Структура цикла выглядит так:

for <переменная> = <начальное значение>, <конечное значение> [, <шаг>] do
  <тело цикла>
end

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

Используя эту конструкцию, мы сможем сократить код приветствий до такого:

for i = 1, 5 do
  print("Hello!")
end

Вот это уже выглядит куда лучше. А самое главное - код получился гораздо гибче. Можно быстро и удобно менять число приветствий. Более того, его можно вынести в переменную, и менять из программы, динамически:

local x = 10
for i = 1, x do
  print("Hello!")
end

Переменная i создаётся интерпретатором автоматически, если нужно. Эта переменная - счётчик цикла.

Интерпретатор даёт ей указанное начальное значение, а потом прибавляет по единичке, пока она не станет равна конечному значению. После этого цикл завершается.

Например, если мы напишем:

for i = 1, to 4 do print(i) end

То в консоль будет выведено:

1
2
3
4

Вы возможно уже заметили, что циклы подчиняются примерно тем же правилам что и условия.

Код внутри цикла (тело), пишется с отступом в два пробела. А если код короткий, его можно написать в одну строку.

В качестве названия для счётчика традиционно используются буквы i, j, k. Однако это не обязательно. Например, при переборе координат удобно назвать счётчик x, y или z.

Последний параметр позволяет влиять на то, как именно будет изменяться счетчик по ходу цикла. По умолчанию - счётчик с каждым разом увеличивается на единицу.

Попробуем изменить шаг:

for i = 10, 20, 5 do print(i) end

В консоли отобразится:

10
15
20

Счётчик начался с 10, и каждый раз увеличивался на 5. Когда он стал равен 20, цикл закончился.

Аналогично можно сделать цикл, счётчик которого будет изменяться от большего к меньшему, а не наоборот:

for i = 5, 1, -1 do print(i) end

Цикл while

Этот цикл немного более универсален. Он повторяет код не по счётчику, а до тех пор, пока не выполнится заданное условие.

Устроен он так:

while <логические выражение> do
  <тело цикла>
end

До тех пор, пока логическое выражение возвращает true, код внутри цикла будет выполняться, раз за разом.

Например, можно "эмулировать" работу цикла for:

local i = 0
while i < 5 do
  print("Hello!")
  i = i + 1
end

Результат будет тем же - пять приветствий. Но выглядит это уже не так лаконично.

Условия могут быть достаточно сложными:

local x, y = 1, 1
while x <= 3 and y <= 3 do
  if x == 3 then
    x = 1
    y = y + 1
  end
  print(x, y)
  x = x + 1
end

Тут у нас и цикл со сложным составным условием, и if который изменяет значения переменных прямо посреди итерации (выполнения цикла).

Когда одна сложная конструкция находится внутри другой, их отступы складываются.

В нашем случае, внутренний if уже имеет отступ в 4 пробела.

Вечные циклы и break

Применив некоторую фантазию (или неосторожность), оба варианта цикла можно написать так, что они будут выполняться вечно:

for i = 1, -1 do
  print("Hello!")
end

Или:

while true do
  print("Hello!")
end

Обычно это приводит к тому, что компьютер вылетает с ошибкой.

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

Пример - компьютерная игра. Основной цикл, который отвечает за игровой процесс должен выполняться всё время пока пользователь играет. Он должен завершиться, когда пользователь нажмёт кнопку "Выход" Но когда это произойдёт - не известно.

Чаще всего в таких случаях используют вариант while true. А затем, по нажатию кнопки прерывают его.

Как же прервать цикл, если вы не хотите ждать его завершения, или если его надо завершить досрочно?

Для этого предназначено ключевое слово break. Как только интерпретатор доходит до команды break, цикл в теле которого расположена эта команда тут же завершается, и программа продолжает выполняться со следующей команды после цикла.

На этом введение в циклы и условия можно считать завершённым. Осталось рассмотреть только использование цикла for на таблицах. Об этом - в следующей главе.

results matching ""

    No results matching ""