Szukaj…


Generic For Loop

Iteratory wykorzystują formę pętli for znaną jako ogólna pętla for .

Ogólna forma pętli for wykorzystuje trzy parametry:

  1. Funkcja iteratora, która jest wywoływana, gdy potrzebna jest następna wartość. Odbiera zarówno niezmienny stan, jak i zmienną kontrolną jako parametry. nil zakończenie sygnałów nil .
  2. Niezmienny stan to wartość, która nie zmienia się podczas iteracji. Zazwyczaj jest to temat iteratora, taki jak tabela, ciąg lub dane użytkownika.
  3. Zmienna kontrolna reprezentuje wartość początkową dla iteracji.

Możemy napisać pętlę for , aby iterować wszystkie pary klucz-wartość w tabeli za pomocą następnej funkcji.

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

Standardowe iteratory

Standardowa biblioteka Lua udostępnia dwie funkcje iteratora, których można używać z pętlą for do przechodzenia między parami klucz-wartość w tabelach.

Do iteracji po tabeli sekwencji możemy użyć funkcji biblioteki 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

Do iteratora po wszystkich kluczach i wartościach w dowolnej tabeli możemy użyć par funkcji bibliotecznych.

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

Iteratory bezstanowe

Zarówno pary, jak i ipairs reprezentują iteratory bezstanowe. Iterator bezstanowy używa tylko ogólnej zmiennej kontrolnej pętli i stanu niezmiennego do obliczenia wartości iteracji.

Pary Iterator

Możemy zaimplementować iterator pairs bezstanowych za pomocą next funkcji.

-- 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 Iterator

Możemy zaimplementować bezstanowy iterator ipairs w dwóch osobnych funkcjach.

-- 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

Iterator postaci

Możemy tworzyć nowe iteratory bezstanowe, wypełniając umowę standardową for pętli.

-- 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

Iterator liczb pierwszych

To jeszcze jeden prosty przykład iteratora bezstanowego.

-- 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

Stanowe iteratory

Stanowe iteratory niosą ze sobą dodatkowe informacje o bieżącym stanie iteratora.

Korzystanie z tabel

Stan dodawania można spakować do stanu ogólnego dla niezmiennego stanu pętli .

  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

Korzystanie z zamknięć

Dodatkowy stan może być zawarty w zamknięciu funkcji. Ponieważ stan jest w pełni objęty zakresem zamknięcia, niezmienny stan i zmienna kontrolna nie są potrzebne.

  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

Używanie coroutines

Dodatkowy stan może być zawarty w coroutine, znowu stan niezmienny i zmienna kontrolna nie są potrzebne.

  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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow