Ricerca…


Ciclo generico

Gli iteratori utilizzano una forma del ciclo for noto come loop generico .

La forma generica del ciclo for utilizza tre parametri:

  1. Una funzione iteratrice che viene chiamata quando è necessario il valore successivo. Riceve sia lo stato invariante che la variabile di controllo come parametri. Restituzione della terminazione dei segnali nil .
  2. Lo stato invariante è un valore che non cambia durante l'iterazione. In genere è l'oggetto dell'iteratore, ad esempio una tabella, una stringa o un dato utente.
  3. La variabile control rappresenta un valore iniziale per l'iterazione.

Possiamo scrivere un ciclo for per iterare tutte le coppie chiave-valore in una tabella usando la funzione successiva .

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

Iteratori standard

La libreria standard Lua fornisce due funzioni di iteratore che possono essere utilizzate con un ciclo for per attraversare coppie di valori-chiave all'interno di tabelle.

Per scorrere su una tabella di sequenze possiamo usare la funzione di libreria 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

Per iteratore su tutte le chiavi e i valori in qualsiasi tabella possiamo usare le coppie di funzioni della libreria.

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

Iteratori apolidi

Sia le coppie che gli ipers rappresentano gli iteratori senza stato. Un iteratore senza stato utilizza solo il generico per la variabile di controllo del ciclo e lo stato invariante per calcolare il valore di iterazione.

Coppie Iterator

Possiamo implementare l'iteratore di pairs senza stato utilizzando la funzione 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

Ipatori Iterator

Siamo in grado di implementare l'iteratore stateless ipairs in due funzioni separate.

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

Iteratore di caratteri

Siamo in grado di creare nuovi iteratori apolidi adempiendo il contratto del generico for ciclo.

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

Questo è un esempio più semplice di un iteratore senza stato.

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

Iteratori di stato

Gli iteratori di stato contengono alcune informazioni aggiuntive sullo stato corrente dell'iteratore.

Utilizzo delle tabelle

Lo stato di aggiunta può essere impacchettato nello stato invariante del ciclo generico .

  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

Utilizzando le chiusure

Lo stato aggiuntivo può essere avvolto all'interno di una chiusura di funzione. Poiché lo stato è completamente contenuto nello scopo della chiusura, lo stato invariante e la variabile di controllo non sono necessari.

  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

Usando le coroutine

Uno stato addizionale può essere contenuto all'interno di una coroutine, di nuovo lo stato invariante e la variabile di controllo non sono necessari.

  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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow