Поиск…


Общий для цикла

Итераторы используют форму цикла for известного как общий для цикла .

Общая форма цикла for использует три параметра:

  1. Функция итератора , вызываемая при следующем значении. В качестве параметров он получает как инвариантное состояние, так и управляющую переменную. Возврат nil сигнала.
  2. Инвариантное состояние - это значение, которое не изменяется во время итерации. Обычно он является объектом итератора, например таблицы, строки или пользовательских данных.
  3. Управляющая переменная представляет собой начальное значение для итерации.

Мы можем написать цикл for для итерации всех пар ключ-значение в таблице с использованием следующей функции.

local t = {a=1, b=2, c=3, d=4, e=5}

-- next is the iterator function
-- t is the invariant state
-- nil is the control variable (calling next with a nil gets the first key)
for key, value in next, t, nil do
  -- key is the new value for the control variable
  print(key, value) 
  -- Lua calls: next(t, key)  
end

Стандартные итераторы

Стандартная библиотека Lua предоставляет две функции итератора, которые могут использоваться с циклом for чтобы пересекать пары ключ-значение в таблицах.

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

for index, value in ipairs {'a', 'b', 'c', 'd', 'e'} do
  print(index, value)  --> 1 a, 2 b, 3 c, 4 d, 5 e
end

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

for key, value in pairs {a=1, b=2, c=3, d=4, e=5} do
  print(key, value)  --> e 5, c 3, a 1, b 2, d 4  (order not specified)
end

Итераторы без гражданства

Обе пары и ipairs представляют итераторы без атак . Итератор без сохранения состояния использует только общие для управляющей переменной цикла и инвариантного состояния для вычисления значения итерации.

Пары Итератор

Мы можем реализовать итератор pairs апатридов, используя next функцию.

-- generator function which initializes the generic for loop
local function pairs(t)
  -- next is the iterator function
  -- t is the invariant state
  -- control variable is nil
  return next, t, nil
end

Итератор Ipairs

Мы можем реализовать ipairs без ipairs в двух отдельных функциях.

-- function which performs the actual iteration
local function ipairs_iter(t, i)
  local i = i + 1  -- next index in the sequence (i is the control variable)
  local v = t[i]   -- next value (t is the invariant state)
  if v ~= nil then
    return i, v    -- index, value
  end
  return nil       -- no more values (termination)
end

-- generator function which initializes the generic for loop
local function ipairs(t)
  -- ipairs_iter is the iterator function
  -- t is the invariant state (table to be iterated)
  -- 0 is the control variable (first index)
  return ipairs_iter, t, 0
end

Итератор символов

Мы можем создать новые итераторы без сохранения состояния, выполнив контракт генератора for цикла.

-- function which performs the actual iteration
local function chars_iter(s, i)
  if i < #s then
    i = i + 1
    return i, s:sub(i, i)
  end
end

-- generator function which initializes the generic for loop
local function chars(s)
  return chars_iter, s, 0
end

-- used like pairs and ipairs
for i, c in chars 'abcde' do
    print(i, c) --> 1 a, 2 b, 3 c, 4 f, 5 e
end

Имитатор первичных чисел

Это еще один простой пример итератора без состояния.

-- prime numbers iterator
local incr = {4, 1, 2, 0, 2}
function primes(s, p, d)
   s, p, d = s or math.huge, p and p + incr[p % 6] or 2, 1
   while p <= s do
      repeat
         d = d + incr[d % 6]
         if d*d > p then return p end
      until p % d == 0
      p, d = p + incr[p % 6], 1
   end
end

-- print all prime numbers <= 100
for p in primes, 100 do  -- passing in the iterator (do not call the iterator here)
   print(p)  -->  2  3  5  7  11 ... 97
end

-- print all primes in endless loop
for p in primes do  -- please note: "in primes", not "in primes()"
   print(p)
end

Истребители состояния

Истираторы состояния содержат дополнительную информацию о текущем состоянии итератора.

Использование таблиц

Состояние добавления может быть упаковано в общий для инвариантного состояния цикла .

  local function chars_iter(t, i)
    local i = i + 1
    if i <= t.len then
      return i, t.s:sub(i, i)
    end
  end

  local function chars(s)
    -- the iterators state
    local t = {
      s = s,    -- the subject
      len = #s  -- cached length
    }
    return chars_iter, t, 0
  end

  for i, c in chars 'abcde' do
    print(i, c) --> 1 a, 2 b, 3 c, 4 d, 5 e
  end

Использование закрытий

Дополнительное состояние можно обернуть в пределах закрытия функции. Поскольку состояние полностью содержится в объеме замыкания, инвариантное состояние и управляющая переменная не нужны.

  local function chars(s)
    local i, len = 0, #s
    return function() -- iterator function
      i = i + 1
      if i <= len then
        return i, s:sub(i, i)
      end
    end
  end

  for i, c in chars 'abcde' do
    print(i, c) --> 1 a, 2 b, 3 c, 4 d, 5 e
  end

Использование Coroutines

Дополнительное состояние может содержаться внутри сопрограммы, снова не требуется инвариантное состояние и управляющая переменная.

  local function chars(s)
    return coroutine.wrap(function()
      for i = 1, #s do
        coroutine.yield(s:sub(i, i))
      end
    end)
  end

  for c in chars 'abcde' do
    print(c) --> a, b, c, d, e
  end


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow