Lua - Iteratory
Iterator to konstrukcja umożliwiająca przechodzenie przez elementy tzw. Kolekcji lub kontenera. W Lua te kolekcje często odnoszą się do tabel, które służą do tworzenia różnych struktur danych, takich jak tablice.
Generic For Iterator
Ogólny dla iteratora zawiera pary klucz-wartość każdego elementu w kolekcji. Poniżej podano prosty przykład.
array = {"Lua", "Tutorial"}
for key,value in ipairs(array)
do
print(key, value)
end
Kiedy uruchomimy powyższy kod, otrzymamy następujący wynik -
1 Lua
2 Tutorial
Powyższy przykład używa domyślnej funkcji iteratora ipairs dostarczonej przez Lua.
W Lua używamy funkcji do reprezentowania iteratorów. W oparciu o utrzymanie stanu w tych funkcjach iteratorów mamy dwa główne typy -
- Iteratory bezpaństwowe
- Iteratory stanowe
Iteratory bezpaństwowe
Z samej nazwy możemy zrozumieć, że tego typu funkcja iteratora nie zachowuje żadnego stanu.
Zobaczmy teraz przykład tworzenia własnego iteratora przy użyciu prostej funkcji, która wypisuje kwadraty n liczby.
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
Kiedy uruchomimy powyższy program, otrzymamy następujące dane wyjściowe.
1 1
2 4
3 9
Powyższy kod można nieco zmodyfikować, aby naśladować sposób działania iteratorów ipairs . Jest to pokazane poniżej.
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
Kiedy uruchomimy powyższy program, otrzymamy następujące dane wyjściowe.
1 1
2 4
3 9
Iteratory stanowe
Poprzedni przykład iteracji z użyciem funkcji nie zachowuje stanu. Za każdym razem, gdy funkcja jest wywoływana, zwraca następny element kolekcji na podstawie drugiej zmiennej wysłanej do funkcji. Aby utrzymać stan bieżącego elementu, używane są zamknięcia. Zamknięcie zachowuje wartości zmiennych w wywołaniach funkcji. Aby utworzyć nowe zamknięcie, tworzymy dwie funkcje, w tym samo zamknięcie i fabrykę, funkcję, która tworzy zamknięcie.
Zobaczmy teraz przykład tworzenia własnego iteratora, w którym będziemy używać domknięć.
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
Kiedy uruchomimy powyższy program, otrzymamy następujące dane wyjściowe.
Lua
Tutorial
W powyższym przykładzie widzimy, że elementIterator ma inną metodę wewnątrz, która używa indeksu i licznika lokalnych zmiennych zewnętrznych, aby zwrócić każdy element w kolekcji, zwiększając indeks za każdym razem, gdy funkcja jest wywoływana.
Możemy tworzyć własne iteratory funkcji za pomocą zamknięcia, jak pokazano powyżej, i może ono zwracać wiele elementów za każdym razem, gdy iterujemy po kolekcji.