Sök…


Generic For Loop

Iteratorer använder en form av for loop som kallas generisk för loop .

Den generiska formen för for loop använder tre parametrar:

  1. En iteratorfunktion som kallas när nästa värde behövs. Den får både invarianttillståndet och kontrollvariabeln som parametrar. Återvändning av nil signalerar avslutningen.
  2. Det invarianta tillståndet är ett värde som inte förändras under iterationen. Det är vanligtvis ämnet för iteratorn, till exempel en tabell, sträng eller userdata.
  3. Kontrollvariabeln representerar ett initialvärde för iteration.

Vi kan skriva en for loop för att iterera alla nyckelvärdespar i en tabell med nästa funktion.

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

Standard Iteratorer

Lua standardbiblioteket har två iteratorfunktioner som kan användas med en for slinga för att korsa nyckelvärdespar inom tabeller.

För att iterera över en sekvenstabell kan vi använda biblioteksfunktionen 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

Till iterator över alla nycklar och värden i någon tabell vi kan använda biblioteksfunktion paren .

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

Statslösa Iteratorer

Både par och ipairs representerar statslösa iteratorer. En statslös iterator använder bara det generiska för loopens styrvariabel och ovariga tillstånd för att beräkna iterationsvärdet.

Par Iterator

Vi kan implementera de statslösa pairs iteratorn med next funktion.

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

Vi kan implementera den statslösa ipairs iteratorn i två separata funktioner.

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

Karaktär Iterator

Vi kan skapa nya statslösa iteratorer genom att uppfylla avtalet med generiska for slinga.

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

Detta är ett mer enkelt exempel på en statslös iterator.

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

Statliga Iteratorer

Statliga iteratorer innehåller ytterligare information om iteratorns nuvarande tillstånd.

Använda tabeller

Tilläggstillståndet kan förpackas i det generiska för loopens invarianttillstånd.

  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

Använda stängningar

Ytterligare tillstånd kan lindas i en funktionsstängning. Eftersom staten helt och hållet ingår i stängningsomfånget behövs inte det invarianta tillståndet och kontrollvariabeln.

  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

Använda Coroutines

Ytterligare tillstånd kan inneslutas i en koroutin, återigen behövs inte det invarianta tillståndet och kontrollvariabeln.

  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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow