... until the first nil element.
An iterator is an object that can be used to traverse some or all elements in a standard template library container. Each iterator object represents a definite address in the container.
In Lua, an iterator is a structure that supports pointer types. It can traverse every element of a collection.
Generic for Iterator
Generic for stores the iterator function internally. In fact, it stores three values: the iterator function, the state constant, and the control variable.
The generic for iterator provides key/value pairs of the collection. The syntax is as follows:
for k, v in pairs(t) do
print(k, v)
end
In the above code, k, v are the variable list; pairs(t) is the expression list.
Look at the following example:
Example
for key,value in ipairs(array)
do
print(key, value)
end
The output of the above code execution is:
1 Google 2 Example
In the above example, we used the iterator function ipairs provided by Lua by default.
Now let's look at the execution process of generic for:
- First, initialize: evaluate the expression after `in`. The expression should return the three values needed by generic for: the iterator function, the state constant, and the control variable. As with multiple assignment, if the expression returns fewer than three values, the missing ones are automatically filled with nil, and extra values are ignored.
- Second, call the iterator function with the state constant and control variable as arguments (note: for the for structure, the state constant is useless; it is only obtained during initialization and passed to the iterator function).
- Third, assign the values returned by the iterator function to the variable list.
- Fourth, if the first returned value is nil, the loop ends; otherwise, execute the loop body.
- Fifth, return to the second step and call the iterator function again.
In Lua, we often use functions to describe iterators. Each time the function is called, it returns the next element of the collection. Lua iterators include the following two types:
- Stateless iterators
- Multi-state iterators
Stateless iterators
A stateless iterator is an iterator that does not retain any state. Therefore, in loops, we can use stateless iterators to avoid the extra cost of creating closures.
In each iteration, the iterator function is called with the values of two variables (the state constant and the control variable) as arguments. A stateless iterator can obtain the next element using only these two values.
A typical and simple example of such a stateless iterator is ipairs, which traverses each element of an array whose indices need to be numeric.
The following example uses a simple function to implement an iterator that computes the square of a number n:
Example
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
The output of the above example is:
1 1 2 4 3 9
The iteration state includes the table being traversed (the state constant, which does not change during the loop) and the current index (the control variable). ipairs and the iterator function are both very simple. In Lua, we can implement it like this:
Example
i = i + 1
local v = a[i]
if v then
return i, v
end
end
function ipairs (a)
return iter, a, 0
end
When Lua calls ipairs(a) to start the loop, it obtains three values: the iterator function iter, the state constant a, and the initial value of the control variable 0. Then Lua calls iter(a,0) and returns 1, a
Multi-state iterators
In many cases, iterators need to store multiple pieces of state information rather than simply a state constant and a control variable. The simplest method is to use closures. Another method is to encapsulate all state information into a table and use the table as the iterator's state constant. In this case, since all information can be stored in the table, the iterator function usually does not need a second parameter.
In the following example, we created our own iterator:
Example
function elementIterator (collection)
local index = 0
local count = #collection
-- closure function
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
The output of the above example is:
Google Example
In the above example, we can see that elementIterator uses a closure function to calculate the size of the collection and output each element.
Other extensions