Раздел: CronosPRO Дата редакции: 11.07.2013 id статьи: 1526

Циклы с оператором for в Lua

Оператор for предназначен для организации циклов и допускает две формы записи:
  • простую (числовой for);
  • расширенную (универсальный for).

Простая форма оператора for

Простая форма оператора for имеет следующий вид:
for var = exp1, exp2, exp3 do-- тело цикла
end
Тело цикла выполняется для каждого значения переменной цикла (счётчика) var в интервале от exp1 до exp2, с шагом exp3.

Примечание

  • Шаг может не задаваться. В этом случае он принимается равным 1.

    for i = 1, 10 do -- цикл от 1 до 10 с шагом 1
       MsgBox ("i равно "..i)
    end
    for i = 10, 1, -1 do -- цикл от 10 до 1 с шагом -1
       MsgBox ("i равно "..i)
    end

Обратите внимание

  • Выражения exp1, exp2 и exp3 вычисляются всего один раз, перед началом цикла. Так, в примере ниже, функция f(x) будет вызвана для вычисления верхнего предела цикла только один раз:

    for i = 1, f(x) do -- цикл от 1 до значения, возвращенного функцией f()
       MsgBox ("i равно "..i)
    end
Переменная цикла является локальной для оператора цикла и по его окончании не определена.
for i = 1, 10 do -- цикл от 1 до значения, возвращенного функцией f()
   MsgBox ("i равно "..i)
end
MsgBox ("После выхода из цикла i равно "..i) -- Неверно! i равно nil

Обратите внимание

  • Значение переменной цикла нельзя изменять внутри цикла: последствия такого изменения непредсказуемы.
Для выхода из цикла до его завершения используется оператор break.
a = {3, 5, 8, -6, 5}
for i = 1,#a do -- ищем в массиве отрицательное значение
   if a[i] < 0 then -- если найдено...
      index = i -- сохраняем индекс найденного значения...
      break -- и прерываем цикл
   end
end
MsgBox ("Индекс отрицательного значения: "..index)

Примечание


Расширенная форма оператора for

В расширенной форме оператора for для последовательного получения значений переменной цикла используется вызов итератора. Цикл завершается, когда итератор возвращает nil.

Примечание

  • Под итератором понимается любая конструкция, позволяющая перебирать элементы некоторого набора. При каждом обращении к итератору он возвращает очередной элемент набора. В Lua итераторы обычно реализуются в виде функций.
Расширенная форма оператора for имеет следующий вид:
for var1, var2, …, varN in <explist> do
... -- тело цикла
end
где:
  • var1, var2, ..., varN — список переменных, получающих значения на каждом шаге цикла. Список может состоять из одной или нескольких переменных, разделённых запятыми. Первую в списке переменную называют управляющей переменной цикла. Когда эта переменная получает возвращённое итератором значение nil, цикл завершается. Остальные переменные на ход выполнения цикла влияния не оказывают;
  • <explist> — список выражений, разделённых запятыми. Обычно список состоит из единственного выражения — вызова функции-фабрики итераторов. Такая функция возвращает функцию-итератор, состояние и начальное значение управляющей переменной цикла.
Оператор for в расширенной форме имеет те же особенности, что и числовой for:
  • переменные цикла var1, var2, ..., varN являются локальными для оператора цикла и по его окончании не определены;
  • значения переменных цикла нельзя изменять внутри цикла.
В качестве примера использования расширенной формы оператора for рассмотрим типичный код, выполняющий обход всех полей таблицы.
for key, val in pairs(t) do
   MsgBox ("key == "..key.."; val == "..val)
end
Список переменных в данном примере включает два элемента — key и val. На каждом шаге цикла переменная key получает ключ очередного поля таблицы t, а переменная val — соответствующее ключу значение поля. В список выражений входит только один элемент — вызов функции-фабрики итераторов pairs.

Работает расширенный оператор for следующим образом:

  • Вызывает функцию pairs(t), от которой принимает три значения:
    • стандартную функцию next в качестве итератора;
    • таблицу, которую требуется обойти (t), в качестве состояния;
    • nil в качестве начального значения управляющей переменной цикла.
    Вызов функции pairs выполняется только один раз.
  • Оператор for приступает к выполнению, собственно, итераций цикла:
    • вызывает функцию-итератор next с двумя параметрами: таблицей t и nil. Функция next, вызванная с этими параметрами, возвращает начальный ключ таблицы и соответствующее ему значение (при условии, что таблица не пуста);
    • вновь вызывает функцию next, передавая ей таблицу t и ключ, полученный на первой итерации. Функция next возвращает следующую пару ключ-значение. Этот процесс продолжается до тех пор, пока функция next не вернёт nil.
Описываемые действия можно представить в виде следующего кода:
do
   local f, s, next_key = pairs(t)
   while true do
      local key, val = f(s, next_key)
      next_key = key
      if next_key == nil then break end
      MsgBox("key == "..key.."; val == "..val)
   end
end
Выполняющий все описанные действия цикл for можно реализовать и без использования функции pairs. Известно, что pairs возвращает функцию next и таблицу, которую следует обойти. Поэтому вызов pairs можно заменить списком соответствующих переменных:
for key, val in next, t do
   MsgBox ("key == "..key.."; val == "..val)
end

Примечание

  • Помимо pairs, стандартные библиотеки Lua предоставляют ещё несколько функций-фабрик итераторов. Так, для перебора элементов массива предусмотрена функция ipairs, а для итерирования по строкам файла — функция io.lines.
  • Ряд фабрик итераторов включён и в состав расширений Lua для CronosPRO. Например, метод IO.Folder.Entries позволяет перебирать файлы и папки, метод sys.win32.registry:values — параметры ключа реестра, а свойство RequestTemplateList.Requests — запросы по образцу текущего банка данных.
  • Вы можете создавать свои собственные итераторы и фабрики итераторов. Для получения необходимой информации рекомендуем Вам обратиться к специализированной литературе по программированию на языке Lua.