Итератор — это конструкция, позволяющая перемещаться по элементам так называемой коллекции или контейнера. В Lua эти коллекции часто ссылаются на таблицы, которые используются для создания различных структур данных, таких как массив.
Универсальный для Итератора
Универсальный для итератора предоставляет пары ключ-значение каждого элемента в коллекции. Простой пример приведен ниже.
array = {"Lua", "Tutorial"} for key,value in ipairs(array) do print(key, value) end
Когда мы запустим приведенный выше код, мы получим следующий вывод:
1 Lua 2 Tutorial
В приведенном выше примере используется итератор ipairs по умолчанию, предоставленный Lua.
В Lua мы используем функции для представления итераторов. Основываясь на поддержании состояния в этих функциях итератора, мы имеем два основных типа:
- Итераторы без состояния
- Stateful Iterators
Итераторы без состояния
По самому имени мы можем понять, что этот тип функции итератора не сохраняет никакого состояния.
Давайте теперь посмотрим на пример создания нашего собственного итератора, используя простую функцию, которая печатает квадраты 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
Stateful Iterators
Предыдущий пример итерации с использованием функции не сохраняет состояние. Каждый раз, когда вызывается функция, она возвращает следующий элемент коллекции на основе второй переменной, отправленной в функцию. Для хранения состояния текущего элемента используются замыкания. Закрытие сохраняет значения переменных через вызовы функций. Чтобы создать новое замыкание, мы создаем две функции, включая само замыкание и фабрику, функцию, которая создает замыкание.
Давайте теперь посмотрим на пример создания нашего собственного итератора, в котором мы будем использовать замыкания.
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 есть еще один метод, который использует индекс локальных внешних переменных и count для возврата каждого элемента в коллекции путем увеличения индекса каждый раз, когда вызывается функция.
Мы можем создавать свои собственные итераторы функций, используя замыкание, как показано выше, и оно может возвращать несколько элементов для каждого итерации цикла.