Lua - Iteratori
Iterator è un costrutto che consente di attraversare gli elementi della cosiddetta raccolta o contenitore. In Lua, queste raccolte fanno spesso riferimento a tabelle, che vengono utilizzate per creare varie strutture di dati come array.
Generico per iteratore
Un generico per iteratore fornisce le coppie chiave-valore di ogni elemento nella raccolta. Di seguito viene fornito un semplice esempio.
array = {"Lua", "Tutorial"}
for key,value in ipairs(array)
do
print(key, value)
end
Quando eseguiamo il codice sopra, otterremo il seguente output:
1 Lua
2 Tutorial
L'esempio precedente utilizza la funzione iteratore ipairs predefinita fornita da Lua.
In Lua usiamo le funzioni per rappresentare gli iteratori. Sulla base del mantenimento dello stato in queste funzioni iteratore, abbiamo due tipi principali:
- Iteratori apolidi
- Iteratori con stato
Iteratori apolidi
Dal nome stesso possiamo capire che questo tipo di funzione iteratore non mantiene alcuno stato.
Vediamo ora un esempio di creazione del nostro iteratore utilizzando una semplice funzione che stampa i quadrati di n numeri.
function square(iteratorMaxCount,currentNumber)
if currentNumber<iteratorMaxCount
then
currentNumber = currentNumber+1
return currentNumber, currentNumber*currentNumber
end
end
for i,n in square,3,0
do
print(i,n)
end
Quando eseguiamo il programma precedente, otterremo il seguente output.
1 1
2 4
3 9
Il codice sopra può essere leggermente modificato per imitare il modo in cui funzionano le funzioni ipairs degli iteratori. È mostrato di seguito.
function square(iteratorMaxCount,currentNumber)
if currentNumber<iteratorMaxCount
then
currentNumber = currentNumber+1
return currentNumber, currentNumber*currentNumber
end
end
function squares(iteratorMaxCount)
return square,iteratorMaxCount,0
end
for i,n in squares(3)
do
print(i,n)
end
Quando eseguiamo il programma precedente, otterremo il seguente output.
1 1
2 4
3 9
Iteratori con stato
L'esempio precedente di iterazione utilizzando la funzione non mantiene lo stato. Ogni volta che la funzione viene chiamata, restituisce l'elemento successivo della raccolta in base a una seconda variabile inviata alla funzione. Per mantenere lo stato dell'elemento corrente, vengono utilizzate le chiusure. La chiusura conserva i valori delle variabili tra le chiamate di funzioni. Per creare una nuova chiusura, creiamo due funzioni tra cui la chiusura stessa e una fabbrica, la funzione che crea la chiusura.
Vediamo ora un esempio di creazione del nostro iteratore in cui useremo le chiusure.
array = {"Lua", "Tutorial"}
function elementIterator (collection)
local index = 0
local count = #collection
-- The closure function is returned
return function ()
index = index + 1
if index <= count
then
-- return the current element of the iterator
return collection[index]
end
end
end
for element in elementIterator(array)
do
print(element)
end
Quando eseguiamo il programma precedente, otterremo il seguente output.
Lua
Tutorial
Nell'esempio sopra, possiamo vedere che elementIterator ha un altro metodo all'interno che utilizza l'indice e il conteggio delle variabili esterne locali per restituire ciascuno degli elementi nella raccolta incrementando l'indice ogni volta che viene chiamata la funzione.
Possiamo creare i nostri iteratori di funzioni usando la chiusura come mostrato sopra e può restituire più elementi per ciascuna delle volte in cui iteriamo nella raccolta.