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