Lua入门教程 6.迭代器与泛型for

0x06迭代器与泛型for

所谓迭代器就是一种可以遍历一种集合中所有元素的机制。

迭代器与Closure

每个迭代器都需要在每次成功调用之间保存一些状态,这样才知道下一步进行到何处,而Closure则为这一任务提供了很好的支持。

function value (t)
    local i = 0
    return function ()
            i = i + 1; return t[i]
          end
end

value()在调用时会创建一个Closure,其中的i保存着迭代的索引值,每调用一次会加一,直到最后一个元素,之后将会返回nil

t = {20, 30, 40}
for element in value(t) do
    print(element)
end

a.泛型for

泛型for在循环过程内部保存了迭代器函数。实际上保存着3个值:

  1. 一个迭代器函数
  2. 一个恒定状态
  3. 一个控制变量

泛型for的语法:

for <var-list> in <exp-list> do
    <body>
end

<var-list>是一个或多个变量名的列表,以逗号分隔开
<exp-list>是一个或多个表达式的列表,以逗号分隔开


变量列表的第一个元素称为“控制变量”。循环过程中决不会为nil,因为当其为nil时循环就已经结束了。for做的第一件事情就是对in后面的表达式进行取值,将会返回3个值给for保存。初始化步骤后,for会以恒定状态和控制变量来调用迭代器函数。然后for将迭代器函数返回值赋予变量列表中的变量。若第一个返回值为空则停止循环。

b.无状态的迭代器

一种不保存任何状态的迭代器 (可以在多个循环中使用他而不会有新的Closure开销

这样迭代器的典型例子就是ipairs

a = {"one", "two", "three"}
for i,v in ipairs(a) do
    print(i, v)
end

下面是ipairs的实现

local function iter (a, i)
    i = i + 1
    local v = a[i]
    if v then
        return i,v
    end
function ipairs (a)
    return iter, a, 0
    end

当Lua调用for循环中的ipairs(a)时,他将获得迭代函数,恒定状态a,控制变量的初始值0。Lua调用iter(a,0),得到1,a[1] 继续调用iter(a,2),获得2,a[2]


pairsipairs的区别
pairs的迭代器函数是Lua中的一个基本函数next

c.具有复杂状态的迭代器

迭代器需要保存许多状态,使用Closoure可以将需要的状态保存在恒定状态中

范例代码:

local iterator

function allwords()
    local state = {line = io.read, pos = 1}
    return iterator, state
end

function iterator (state)
    while state.line do  --若为有效行的执行内容就进入循环
        --搜索下一个单词
        local s,e = string.find(state.line, "%w+", state.pos)
        if s then  --找到了一个单词
        --更新下一个位置
            state.pos = e + 1
            return string.sub(state.line, s, e)
        else  --没有找到单词
            state.line = io.read()  --读取下一行
            state.pos = 1          --从第一个位置开始
        end
    end
    return nil
end

真正的迭代器

迭代器并没有做实际的迭代,真正做迭代的是for循环。而迭代器只是每次迭代提供一些成功后的返回值。还有一种创建迭代器的方式:在迭代器中做实际的迭代操作

可以重写allwords()函数

function allwords (f)
for line in io.lines() do
    for word in string.gmatch(line, "%w+") do
        f(word)
    end
end
end

使用这个迭代器时,需要传入一个描述循环体的函数。如果要打印每个单词,那么可以使用print: allwords(print)

猜你喜欢

转载自blog.csdn.net/yao_jianlun/article/details/51712255