lua系统学习13-自定义创建一个迭代器

19 篇文章 0 订阅
14 篇文章 0 订阅

使用Closure特性自己创建迭代器

function IteratorDIY(t1)
    function iteratorTableValue(t)
        local i=0
        return function () i=i+1; return t[i] end
    end
    for i in iteratorTableValue(t1) do
    print(i)
    end

end
IteratorDIY({0,1,2,3,4,5,6,'\\0'});
0
1
2
3
4
5
6
\0

在上面案例中 我们使用了Closure的特性,在一个函数内部定义了局部变量,在尾调用处返回一个匿名函数 在匿名函数中调用了这个在IteratorDIY中的局部变量。还记得之前说到Closure的时候,说这样的写法在匿名函数中会把在IteratorDIY的局部变量看作一个非全局的变量。对于函数内的匿名函数来说它既不是全局变量也不是局部变量,但对于IteratorDIY函数来说却又是局部变量。
接着我们使用for 接收变量 in initializeList do end
在这个示例中initializeList 会返回一个执行函数
这里呢,执行函数会在每次循环前被执行并把输出结果返回接收变量,直到执行函数返回nil的时候 也就接收变量=nil的时候结束循环。
通过这样我们就实现了一个迭代器。
当然我们也可以模拟实现IPair

function IteratorDIY2(t1)
   function iteratorTablePair(t)
       local i=0
       return function () i=i+1;
           if i>#t then
               return nil,nil
           else
               return i,t[i]
           end
       end
   end
   for i,v in iteratorTablePair(t1) do
       print(i,v)
   end
end
IteratorDIY2({0,1,2,3,4,5,6,'\\0'});
1	0
2	1
3	2
4	3
5	4
6	5
7	6
8	\0

for in 循环结束的条件 必须要第一个接收变量为nil的时候才结束
上例中使用条件判断 当“当前累计的i大于长度的时候就返回nil”。
迭代io中所有单词与数字

function IteratorAllWords()

    function wordIterator()
        for word in allWords() do
        print(word)
        end
    end
    function allWords()
        local line=io.read()--他本身也是个迭代器
        local pos=1--- 开始位置
        return function()
            while line do
               local s,e= string.find(line,"%w+",pos)
                if s then
                    pos=e+1---s是字符串的开始索引 e是字符串的长度
                    return string.sub(line,s,e)
                else
                    line=io.read()
                    pos=1
                    if line=='quit' then
                        return nil
                    end
                end
            end
            return nil
        end
    end
    wordIterator()
end
IteratorAllWords()
asdsa23.fg
quit


asdsa23
fg

无状态迭代器

以上的这些示例 都是通过Closure会保存非局部的变量的特性实现的。但是如果每次循环迭代都会创建一个新的Closure就意味着要考虑性能问题了,那么有没有什么好的方案代替呢?
下面不使用Closure,利用For in会接收函数结果的特性来创建一个迭代器。

function ForVar(t)
    function iteratorTablePair(t,i)
        return function () i=i+1;
            if i>#t then
                return nil,nil
            else
                return i,t[i]
            end
        end
    end
    i=0
    for i,v in iteratorTablePair(t,i) do
        print(i,v)
    end

end
    ForVar({2,3,4,5})
1	2
2	3
3	4
4	5

前面说过For varList in initializeList do 这个结构。initializeList
下有三个变量,分别是1.迭代器工厂 2.恒定变量(表)3.控制变量
这三个变量1是必须要写的 后面两个变量如果不写的话 则为nil。
迭代器工厂返回一个迭代器函数
varlist会接收迭代器函数的结果 当varlist[0]的结果为nil,循环为nil。所以我们把varlist中第一个变量称之为循环的控制变量,控制循环的结束。
上面迭代单词的示例中使用的是Closure的非局部变量的保存来实现迭代器,在这个示例中我们可以通过参数传值的方式代替Closure的非局部变量。
利用到Closure无非就是能保存上一次变量计算的值,那么我们直接把返回过来的值再传回去不就好了。
所以就有了 for i in func(t,i) do的实现。
其实还可以更简洁,for in其实在循环过程内部保存了迭代器函数
用Ipair来举例 实际lua中的ipair不会像我们上面写的那些例子那样,它不会有closure的开销。

function ipairNoColsureImplent()
   local function  ipairIter(t,i)
       i=i+1
       local v=t[i]
       if v then
           return i,v
       end
    end

    function dummyIpair(t)
        return ipairIter,t,0
    end
    
    t={"a","b","c"}
    for i,v in dummyIpair(t) do
        print(i,v)
    end
    
end
ipairNoColsureImplent()
1	a
2	b
3	c

dummyIpair返回3个值,第一个是迭代器函数(for每次循环要执行的函数)、第二个是恒定变量,第三是控制变量。
实际上dummyIpair在for初始化时候执行而不是参与循环时候执行,真正参与循环的是dummyipair返回的函数。所以在dummyipair中返回恒定变量、控制变量 与 for varlist in ipairItera,恒定变量,控制变量 do。 这样的写法是一样的。因为在for in do 中 in的优先级是最高的,可以理解为迭代器初始化,
然后才进行循环。
示例:

function ipairNoColsureImplent2()
    local function  ipairIter(t,i)
        i=i+1
        local v=t[i]
        if v then
            return i,v
        end
    end

    t={"a","b","c"}
    for i,v in ipairIter,t,0 do
        print(i,v)
    end
end

我们可以称dummyipair为迭代器的工厂,用来创建迭代器的。
在lua中会把恒定变量与控制变量的值,作为参数在第一次执行迭代器即ipairIter函数时候传入进去。
因为迭代器会返回控制变量的值,所以后面for in会自动把恒定变量和控制变量i再作为参数传入迭代器进行迭代。(此步骤是由for in 传入参数,不是从迭代器的工厂传入)

pair的实现

function pairNoColsureImplent()
    function dummyPair(t)
        return next,t,nil
    end
    t={"a","b","c",1,2}
    for i,v in dummyPair(t) do
        print(i,v)
    end
end
pairNoColsureImplent()
1	a
2	b
3	c
4	1
5	2

pair中用到了lua自带的next函数。用来访问table下一个元素
就有点像地址下移似的。这个直接通过操作指针应该也是可以的。

复杂状态的迭代器

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值