Lua - Итераторы
Итератор - это конструкция, которая позволяет вам перемещаться по элементам так называемой коллекции или контейнера. В Lua эти коллекции часто относятся к таблицам, которые используются для создания различных структур данных, таких как массив.
Generic для итератора
Общий для итератора предоставляет пары ключ-значение каждого элемента в коллекции. Ниже приводится простой пример.
array = {"Lua", "Tutorial"}
for key,value in ipairs(array)
do
print(key, value)
end
Когда мы запустим приведенный выше код, мы получим следующий вывод -
1 Lua
2 Tutorial
В приведенном выше примере используется функция итератора ipairs по умолчанию, предоставляемая Lua.
В Lua мы используем функции для представления итераторов. Основываясь на поддержании состояния в этих функциях итератора, у нас есть два основных типа:
- Итераторы без сохранения состояния
- Итераторы с отслеживанием состояния
Итераторы без сохранения состояния
По самому названию мы можем понять, что этот тип функции итератора не сохраняет никакого состояния.
Давайте теперь посмотрим на пример создания нашего собственного итератора с помощью простой функции, которая печатает квадраты n числа.
function square(iteratorMaxCount,currentNumber)
if currentNumber<iteratorMaxCount
then
currentNumber = currentNumber+1
return currentNumber, currentNumber*currentNumber
end
end
for i,n in square,3,0
do
print(i,n)
end
Когда мы запустим вышеуказанную программу, мы получим следующий результат.
1 1
2 4
3 9
Приведенный выше код можно немного изменить, чтобы имитировать работу итераторов ipairs . Это показано ниже.
function square(iteratorMaxCount,currentNumber)
if currentNumber<iteratorMaxCount
then
currentNumber = currentNumber+1
return currentNumber, currentNumber*currentNumber
end
end
function squares(iteratorMaxCount)
return square,iteratorMaxCount,0
end
for i,n in squares(3)
do
print(i,n)
end
Когда мы запустим вышеуказанную программу, мы получим следующий результат.
1 1
2 4
3 9
Итераторы с отслеживанием состояния
Предыдущий пример итерации с использованием функции не сохраняет состояние. Каждый раз, когда вызывается функция, она возвращает следующий элемент коллекции на основе второй переменной, отправленной в функцию. Для удержания состояния текущего элемента используются замыкания. Замыкание сохраняет значения переменных между вызовами функций. Чтобы создать новое замыкание, мы создаем две функции, включая само замыкание и фабрику, функцию, которая создает замыкание.
Давайте теперь посмотрим на пример создания нашего собственного итератора, в котором мы будем использовать замыкания.
array = {"Lua", "Tutorial"}
function elementIterator (collection)
local index = 0
local count = #collection
-- The closure function is returned
return function ()
index = index + 1
if index <= count
then
-- return the current element of the iterator
return collection[index]
end
end
end
for element in elementIterator(array)
do
print(element)
end
Когда мы запустим вышеуказанную программу, мы получим следующий результат.
Lua
Tutorial
В приведенном выше примере мы видим, что elementIterator имеет внутри другой метод, который использует локальные внешние переменные index и count для возврата каждого элемента в коллекции путем увеличения индекса при каждом вызове функции.
Мы можем создавать наши собственные итераторы функций, используя замыкание, как показано выше, и оно может возвращать несколько элементов каждый раз, когда мы перебираем коллекцию.