Recherche…


Générique pour boucle

Les itérateurs utilisent une forme de la boucle for connue sous le nom de boucle générique .

La forme générique de la boucle for utilise trois paramètres:

  1. Une fonction itérateur appelée lorsque la valeur suivante est requise. Il reçoit à la fois l'état invariant et la variable de contrôle en tant que paramètres. De retour nil terminaison de signaux.
  2. L' état invariant est une valeur qui ne change pas pendant l'itération. Il s'agit généralement du sujet de l'itérateur, tel qu'une table, une chaîne ou des données utilisateur.
  3. La variable de contrôle représente une valeur initiale pour l'itération.

Nous pouvons écrire une boucle for pour parcourir toutes les paires clé-valeur dans une table en utilisant la fonction suivante .

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

Itérateurs standard

La bibliothèque standard Lua fournit deux fonctions d'itérateur qui peuvent être utilisées avec une boucle for pour parcourir des paires clé-valeur dans des tables.

Pour parcourir une table de séquence, nous pouvons utiliser la fonction de bibliothèque 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

Pour itérer toutes les clés et valeurs de n'importe quelle table, nous pouvons utiliser les paires de fonctions de bibliothèque.

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

Itérateurs sans état

Les deux paires et ipairs représentent des itérateurs sans état. Un itérateur sans état utilise uniquement la variable de contrôle et l'état invariant génériques de la boucle pour calculer la valeur d'itération.

Itérateur de paires

Nous pouvons implémenter l'itérateur de pairs sans état en utilisant la fonction 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 Iterator

Nous pouvons implémenter l'itérateur ipairs sans ipairs dans deux fonctions distinctes.

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

Itérateur de personnage

Nous pouvons créer de nouveaux itérateurs apatrides en remplissant le contrat du générique for la boucle.

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

Itérateur de nombres premiers

C'est un exemple plus simple d'itérateur sans état.

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

Les itérateurs

Les itérateurs à états contiennent des informations supplémentaires sur l'état actuel de l'itérateur.

Utiliser des tables

L'état d'addition peut être compressé dans le générique pour l' état invariant de la boucle .

  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

Utiliser des fermetures

L'état supplémentaire peut être enveloppé dans une fermeture de fonction. Puisque l'état est entièrement contenu dans la portée de la fermeture, l'état invariant et la variable de contrôle ne sont pas nécessaires.

  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

Utiliser Coroutines

Un état supplémentaire peut être contenu dans une coroutine, là encore, l'état invariant et la variable de contrôle ne sont pas nécessaires.

  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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow