Раздел: 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)
Примечание
- Подробнее об особенностях использования оператора break — в статье «Операторы break и return» (id: 1527).
Расширенная форма оператора 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 в качестве начального значения управляющей переменной цикла.
- Оператор 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.