Учебники

Lua — Итераторы

Итератор — это конструкция, позволяющая перемещаться по элементам так называемой коллекции или контейнера. В Lua эти коллекции часто ссылаются на таблицы, которые используются для создания различных структур данных, таких как массив.

Универсальный для Итератора

Универсальный для итератора предоставляет пары ключ-значение каждого элемента в коллекции. Простой пример приведен ниже.

Live Demo

array = {"Lua", "Tutorial"}

for key,value in ipairs(array) 
do
   print(key, value)
end

Когда мы запустим приведенный выше код, мы получим следующий вывод:

1  Lua
2  Tutorial

В приведенном выше примере используется итератор ipairs по умолчанию, предоставленный Lua.

В Lua мы используем функции для представления итераторов. Основываясь на поддержании состояния в этих функциях итератора, мы имеем два основных типа:

  • Итераторы без состояния
  • Stateful Iterators

Итераторы без состояния

По самому имени мы можем понять, что этот тип функции итератора не сохраняет никакого состояния.

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

Live Demo

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 функции итераторов. Это показано ниже.

Live Demo

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

Предыдущий пример итерации с использованием функции не сохраняет состояние. Каждый раз, когда вызывается функция, она возвращает следующий элемент коллекции на основе второй переменной, отправленной в функцию. Для хранения состояния текущего элемента используются замыкания. Закрытие сохраняет значения переменных через вызовы функций. Чтобы создать новое замыкание, мы создаем две функции, включая само замыкание и фабрику, функцию, которая создает замыкание.

Давайте теперь посмотрим на пример создания нашего собственного итератора, в котором мы будем использовать замыкания.

Live Demo

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

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