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

Мы можем создавать наши собственные итераторы функций, используя замыкание, как показано выше, и оно может возвращать несколько элементов каждый раз, когда мы перебираем коллекцию.