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 для возврата каждого элемента в коллекции путем увеличения индекса при каждом вызове функции.
Мы можем создавать наши собственные итераторы функций, используя замыкание, как показано выше, и оно может возвращать несколько элементов каждый раз, когда мы перебираем коллекцию.