Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
[Обучение] Основы Lua.docx
Скачиваний:
1
Добавлен:
01.05.2025
Размер:
66.67 Кб
Скачать

Итераторы

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

for v_1, v_2, ..., v_n in explist do ... end

Число переменных в списке v_1, ..., v_n может быть произвольным и не обязано соответствовать числу выражений в списке explist. В роли explist обычно выступает вызов фунции-фабрики итераторов. Такая функция возвращает функцию-итератор, состояние и начальное значение управляющей переменной цикла. Итератор интерпретируется следующим образом:

do

local f, s, v_1 = explist

local v_2, ... , v_n

while true do

v_1, ..., v_n = f(s, v_1)

if v_1 == nil then break end

...

end

end

На каждом шаге значения всех переменных v_k вычисляются путем вызова функции-итератора. Значение управляющей переменной v_1 управляет завершением цикла  —  цикл завершается как только функция-итератор возвратит nil как значение для переменной var_1.

Фактически итерациями управляет переменная v_1, а остальные переменные можно рассматривать как «хвост», возвращаемый функцией-итератором:

do

local f, s, v = explist

while true do

v = f(s, v)

if v == nil then break end

...

end

end

Оператор, в котором вызывается функция-фабрика, интерпретируется как обычный оператор присваивания т.е. функция-фабрика может возвращать произвольное количество значений.

Итераторы без внутреннего состояния

Итератор без внутреннего состояния не хранит никакой внутренней информации, позволяющей ему определить свое положение в итерируемом контейнере. Следующее значение управляющей переменной вычисляется непосредственно по ее предыдущему значению, а состояние используется для хранения ссылки на итерируемый контейнер. Вот пример простого итератора без внутреннего состояния:

function iter( a, i )

i = i + 1

local v = a[i]

if v then

return i, v

else

return nil

end

end

function ipairs( a )

return iter, a, 0

end

Итераторы, хранящие состояние в замыкании

Если итератору для обхода контейнера необходимо внутреннее состояние, то проще всего хранить его в замыкании, создаваемом по контексту функции-фабрики. Вот простой пример:

function ipairs( a )

local i = 0

local t = a

local function iter()

i = i + 1

local v = t[i]

if v then

return i, v

else

return nil

end

end

return iter

end

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

Стандартные итераторы

Чаще всего итераторы применяются для обхода элементов таблиц. Для этого существует несколько предопределенных функций-фабрик итераторов. Фабрика pairs(t) возвращает итератор, дающий на каждом шаге индекс в таблице и размещенное по этому индексу значение:

for idx, val in pairs(tbl) do

...

end

На самом деле этот итератор легко определить, используя стандартную функцию next(tbl, idx):

function pairs(tbl)

return next, tbl, nil

end

Функция next(tbl, idx) возвращает следующее за idx значение индекса при некотором обходе таблицы tbl (вызов next(tbl, nil) возвращает начальное значение индекса; после исчерпания элементов таблицы возвращается nil).

Фабрика ipairs(tbl) возвращает итератор, работающий совершенно аналогично описанному выше, но предназначенный для обхода таблиц, проиндексированные целыми числами начиная с 1.