An iterator is an object that can be used to traverse some or all of the elements in a standard template library container. Each iterator object represents a certain address in the container.
In Lua, an iterator is a type that supports pointers. A structure that iterates over each element of the collection.
Generic for iterator
The generic for saves the iteration function inside itself, in fact it saves three values: the iteration function, the state constant, and the control variable.
The generic for iterator provides a set of key/value pairs, the syntax is as follows:
for k, v in pairs(t) do
print(k, v)
end
In the above code, k, v is a list of variables; pairs(t) is a list of expressions. Check out the examples below:
array = {"Lua", "Tutorial"}
for key,value in ipairs(array)
do
print(key, value)
end
The output of the above code execution is:
1 Lua
2 Tutorial
In the above example, we used the iterative function ipairs provided by Lua by default.
Let's take a look at the execution process of the generic for:
- First, initialize, calculate the value of the expression after in, the expression should return
the three values required by the generic for: iterative function, state constant, control variable; like multi-value assignment, if the number of results returned by the expression is less than three Each will be automatically filled with nil, and the extra part will be ignored. - Second, call the iterative function with the state constant and the control variable as parameters (note: for the for structure, the state constant is not useful, just get its value at initialization and pass it to the iterative function).
- Third, assign the value returned by the iteration function to the list of variables.
- Fourth, if the first value returned is nil, the loop ends, otherwise the loop body is executed.
- Fifth, go back to the second step and call the iterative function again
In Lua we often describe iterators as functions that return the next element of the collection each time the function is called. Lua's iterators include the following two types:
- stateless iterator
- multi-state iterator
stateless iterator
A stateless iterator is an iterator that does not retain any state, so we can use stateless iterators in loops to avoid the extra cost of creating closures.
Each iteration, the iteration function is called with the values of two variables (state constant and control variable) as arguments, and a stateless iterator uses only these two values to get the next element.
A typical simple example of such stateless iterators are ipairs, which iterate over each element of an array.
In the following example we use a simple function to implement an iterator to square a number n:
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
The output of the above example is:
1 1
2 4
3 9
The iterative state includes the traversed table (state constant that will not change during the loop) and the current index subscript (control variable), ipairs and iterative functions are very simple, we can achieve this in Lua:
function iter (a, i)
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 gets three values: the iteration function iter, the state constant a, and the initial value of the control variable 0; then Lua calls iter(a,0) to return 1, a[1] (unless a [1]=nil); the second iteration calls iter(a,1) to return 2,a[2]...until the first nil element.
multi-state iterator
In many cases, iterators need to store multiple state information instead of simple state constants and control variables. The easiest way is to use closures. Another way is to encapsulate all state information into a table and use the table as an iterator. The state constant of the controller, because in this case all the information can be stored in the table, so the iterator function usually does not need the second parameter.
The following example we create our own iterator:
array = {"Lua", "Tutorial"}
function elementIterator (collection)
local index = 0
--得到数组的长度
local count = #collection
-- 闭包函数
return function ()
index = index + 1
if index <= count
then
-- 返回迭代器的当前元素
return collection[index]
end
end
end
for element in elementIterator(array)
do
print(element)
end
The output of the above example is:
Lua
Tutorial
The difference between pairs and ipairs
Same: Both can traverse collections (tables, arrays)
Different:
(1)
- pairs: can traverse all the keys in the table can return nil
- ipairs: cannot return nil, if it encounters nil, it will exit
. That is to say, ipairs can only follow the order of 1, 2, 3, 4.... If there is an index jump in the middle, it will interrupt the output, and the first If the index is not 1, nothing is output.
(2)
- ipairs just iterates over the values.
- pairs can iterate over all elements of a collection. That is, pairs can traverse all keys in the collection, and can return nil in addition to the iterator itself and the traversal table itself.
local tab= {
[1] = "a",
[3] = "b",
[4] = "c"
}
for i,v in pairs(tab) do -- 输出 "a" ,"b", "c" ,
print( tab[i] )
end
for i,v in ipairs(tab) do -- 输出 "a" ,k=2时断开
print( tab[i] )
end