Поиск…
Общий для цикла
Итераторы используют форму цикла for
известного как общий для цикла .
Общая форма цикла for
использует три параметра:
- Функция итератора , вызываемая при следующем значении. В качестве параметров он получает как инвариантное состояние, так и управляющую переменную. Возврат
nil
сигнала. - Инвариантное состояние - это значение, которое не изменяется во время итерации. Обычно он является объектом итератора, например таблицы, строки или пользовательских данных.
- Управляющая переменная представляет собой начальное значение для итерации.
Мы можем написать цикл for
для итерации всех пар ключ-значение в таблице с использованием следующей функции.
local t = {a=1, b=2, c=3, d=4, e=5}
-- next is the iterator function
-- t is the invariant state
-- nil is the control variable (calling next with a nil gets the first key)
for key, value in next, t, nil do
-- key is the new value for the control variable
print(key, value)
-- Lua calls: next(t, key)
end
Стандартные итераторы
Стандартная библиотека Lua предоставляет две функции итератора, которые могут использоваться с циклом for
чтобы пересекать пары ключ-значение в таблицах.
Для итерации по таблице последовательностей мы можем использовать библиотечную функцию ipairs .
for index, value in ipairs {'a', 'b', 'c', 'd', 'e'} do
print(index, value) --> 1 a, 2 b, 3 c, 4 d, 5 e
end
Для итератора по всем ключам и значениям в любой таблице мы можем использовать пар функции библиотеки.
for key, value in pairs {a=1, b=2, c=3, d=4, e=5} do
print(key, value) --> e 5, c 3, a 1, b 2, d 4 (order not specified)
end
Итераторы без гражданства
Обе пары и ipairs представляют итераторы без атак . Итератор без сохранения состояния использует только общие для управляющей переменной цикла и инвариантного состояния для вычисления значения итерации.
Пары Итератор
Мы можем реализовать итератор pairs
апатридов, используя next
функцию.
-- generator function which initializes the generic for loop
local function pairs(t)
-- next is the iterator function
-- t is the invariant state
-- control variable is nil
return next, t, nil
end
Итератор Ipairs
Мы можем реализовать ipairs
без ipairs
в двух отдельных функциях.
-- function which performs the actual iteration
local function ipairs_iter(t, i)
local i = i + 1 -- next index in the sequence (i is the control variable)
local v = t[i] -- next value (t is the invariant state)
if v ~= nil then
return i, v -- index, value
end
return nil -- no more values (termination)
end
-- generator function which initializes the generic for loop
local function ipairs(t)
-- ipairs_iter is the iterator function
-- t is the invariant state (table to be iterated)
-- 0 is the control variable (first index)
return ipairs_iter, t, 0
end
Итератор символов
Мы можем создать новые итераторы без сохранения состояния, выполнив контракт генератора for
цикла.
-- function which performs the actual iteration
local function chars_iter(s, i)
if i < #s then
i = i + 1
return i, s:sub(i, i)
end
end
-- generator function which initializes the generic for loop
local function chars(s)
return chars_iter, s, 0
end
-- used like pairs and ipairs
for i, c in chars 'abcde' do
print(i, c) --> 1 a, 2 b, 3 c, 4 f, 5 e
end
Имитатор первичных чисел
Это еще один простой пример итератора без состояния.
-- prime numbers iterator
local incr = {4, 1, 2, 0, 2}
function primes(s, p, d)
s, p, d = s or math.huge, p and p + incr[p % 6] or 2, 1
while p <= s do
repeat
d = d + incr[d % 6]
if d*d > p then return p end
until p % d == 0
p, d = p + incr[p % 6], 1
end
end
-- print all prime numbers <= 100
for p in primes, 100 do -- passing in the iterator (do not call the iterator here)
print(p) --> 2 3 5 7 11 ... 97
end
-- print all primes in endless loop
for p in primes do -- please note: "in primes", not "in primes()"
print(p)
end
Истребители состояния
Истираторы состояния содержат дополнительную информацию о текущем состоянии итератора.
Использование таблиц
Состояние добавления может быть упаковано в общий для инвариантного состояния цикла .
local function chars_iter(t, i)
local i = i + 1
if i <= t.len then
return i, t.s:sub(i, i)
end
end
local function chars(s)
-- the iterators state
local t = {
s = s, -- the subject
len = #s -- cached length
}
return chars_iter, t, 0
end
for i, c in chars 'abcde' do
print(i, c) --> 1 a, 2 b, 3 c, 4 d, 5 e
end
Использование закрытий
Дополнительное состояние можно обернуть в пределах закрытия функции. Поскольку состояние полностью содержится в объеме замыкания, инвариантное состояние и управляющая переменная не нужны.
local function chars(s)
local i, len = 0, #s
return function() -- iterator function
i = i + 1
if i <= len then
return i, s:sub(i, i)
end
end
end
for i, c in chars 'abcde' do
print(i, c) --> 1 a, 2 b, 3 c, 4 d, 5 e
end
Использование Coroutines
Дополнительное состояние может содержаться внутри сопрограммы, снова не требуется инвариантное состояние и управляющая переменная.
local function chars(s)
return coroutine.wrap(function()
for i = 1, #s do
coroutine.yield(s:sub(i, i))
end
end)
end
for c in chars 'abcde' do
print(c) --> a, b, c, d, e
end