English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Итераторы Lua

Итератор(iterator) является объектом, который можно использовать для遍ения части или всех элементов контейнера стандартной библиотеки шаблонов, каждый объект итератора представляет определенный адрес в контейнере.

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

Генерический for-迭代атор

Генерический for-迭代атор сохраняет внутреннюю функцию итерации, фактически он сохраняет три значения: функцию итерации, константный статус и переменную управления.

Генерический for-迭代атор предоставляет пары ключ/значение набора, формат синтаксиса следующий:

for k, v in pairs(t) do
    print(k, v)
end

В данном коде k, v являются списком переменных; pairs(t) является списком выражений.

Смотрите следующий пример:

array = {"Google", "w3codebox"}
for key,value in ipairs(array) 
do
   print(key, value)
end

Результат выполнения кода:

1  Google
2  w3codebox

В предыдущем примере мы использовали стандартную функцию итерации Lua ipairs.

Теперь посмотрим, как выполняется универсальный for:

  • Первый, инициализация, вычислим значение выражения после in, выражение должно вернуть три значения, необходимые для универсального for: функция итерации, константа состояния, контрольная переменная; как и в случае с множественной присваиванием, если выражение возвращает меньше трех значений, они автоматически дополняются nil, избыточные значения игнорируются.

  • Второй, вызовем функцию итерации с константой состояния и контрольной переменной в качестве параметров (обратите внимание: для структуры for константа состояния не имеет значения, она используется только для инициализации и передается функции итерации).

  • Третий, присвоим значения, возвращенные функцией итерации, переменным.

  • Четвертый, если первый возвращаемый значением nil, цикл заканчивается,否则 выполняется тело цикла.

  • Пятый, вернемся ко第二步 и вызовем функцию итерации снова

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

  • Без состояния итератор

  • Итераторы с несколькими состояниями

Без состояния итератор

Без��态ный итератор - это итератор, который не сохраняет никакое состояние, поэтому в цикле мы можем использовать без��态ный итератор, чтобы избежать дополнительных затрат на создание closures.

В каждой итерации функция итерации вызывается с двумя переменными (константа состояния и контрольная переменная) в качестве параметров, без��态ный итератор использует только эти две переменные для получения следующего элемента.

Типичным простым примером такого без��态ного итератора является ipairs, который проходим по каждому элементу массива.

В следующем примере мы используем простую функцию для реализации итератора, чтобы получить квадрат числа n:

функция square(iteratorMaxCount, currentNumber)
   если currentNumber < iteratorMaxCount
   then
      currentNumber = currentNumber + 1
   возврат currentNumber, currentNumber * currentNumber
   end
end
for i, n in square, 3, 0
do
   print(i, n)
end

Приведенные выше примеры выводят результат:

1  1
2  4
3  9

Состояние итерации включает таблицу, которая проходима (состояние константы, которое не изменяется в процессе итерации) и текущий индекс индекса (контрольная переменная), функции ipairs и итерации очень просты, и мы можем реализовать это в Lua следующим образом:

функция iter(a, i)
    i = i + 1
    локальная переменная v = a[i]
    если v то
       возврат i, v
    end
end
 
функция ipairs(a)
    return iter, a, 0
end

Когда Lua вызывает ipairs(a) для начала цикла, он получает три значения: функцию итерации iter, константу состояния a и начальное значение переменной контроля 0; затем Lua вызывает iter(a,0) и возвращает 1, a[1] (если a[1] не nil);第二次 итерация вызывает iter(a,1) и возвращает 2, a[2]……до первого nil элемента.

Итераторы с несколькими состояниями

Во многих случаях итератор должен сохранять несколько состояний, а не просто константы состояния и контролируемые переменные. Самый простой способ - это использование функции-закрытия,还有一种 способ - это封装 всех состояний в таблицу, таблицу как состояние константы итератора, так как в этом случае все данные могут быть сохранены в таблице, поэтому функция итерации обычно не требует второго параметра.

В следующем примере мы создаем свой собственный итератор:

array = {"Google", "w3codebox"}
function elementIterator(collection)
   local index = 0
   local count = #collection
   -- Функция-закрытие
   return function ()
      index = index + 1
      if index <= count
      then
         -- Возвращает текущий элемент итератора
         return collection[index]
      end
   end
end
for element in elementIterator(array)
do
   print(element)
end

Приведенные выше примеры выводят результат:

Google
w3codebox

В приведенных выше примерах мы можем видеть, что в elementIterator используется функция-закрытие, которая реализует вычисление размера集合 и вывод всех элементов.