美文网首页
Lua迭代器与closure

Lua迭代器与closure

作者: 凉拌姨妈好吃 | 来源:发表于2018-06-27 09:13 被阅读0次

预备知识
lua函数是一种First-Class Value,即它与传统的变量并没有什么区别。
它可以存储到变量中、存储到table中、作为实参传递给其他函数、作为其他函数的返回值等。
它们还具有特定的词法域,也就是说,一个函数可以嵌套在另一个函数中,内部函数可以访问外部函数的变量。

1. closure(闭合函数)

1.1 closure的组成

一个closure就是一个函数加上这个函数所需访问的所有"非局部变量",非局部变量也就是外部函数的变量

function newCounter()
   local i = 0
        func = function()
                i = i + 1
                return i
        end
   return func
end
c1 = newCounter()
print(c1())
print(c1())

当我们每次再调用newCounter这个函数的时候,也会得到一个新的closure,这往往是性能损耗的关键。

1.2 upValue

每个闭包都可以有一个upValue值,多个闭包可以共享一个upValue数值
外部函数的局部变量,因为它已经是内部函数的upValue,所以局部变量的生命期延长。当我们不再调用函数,那么闭包就不会再生成,那么此时局部变量的生命期就到了尽头,等待gc回收。

upValue其实就是局部变量,当它还没有离开它的作用域,它就一直生存在堆栈上,闭包通过指向堆栈的引用了来访问它们,一旦upValue即将离开自己的作用域,在从堆栈消除之前,闭包就会为它分配空间并保留当前的值。

1.3闭包生成流程

每当Lua执行一个函数时,它就会创建一个新的数据对象,这个数据对象包含了相应函数原型的引用、环境的引用以及一个由所有upValue引用组成的数组,这个数据对象就称为闭包。

2. 迭代器

2.1 为什么需要迭代器

编程中我们往往碰到各种各样的容器,不一样的容器它们的底层代码实现是不同的,那就意味着,遍历它们需要不同的方式。这样一来非常不利于代码重用,所以迭代器就出现了,我们将遍历容器的操作都封装在迭代器里,那么我们就不需要考虑这个容器需要用哪一种遍历方式。

2.2 什么是迭代器

它是一种可以遍历一种集合所有元素的机制。Lua中迭代器常意味着函数,每调用一次函数,即返回集合的下一个元素。

2.3 迭代器的使用

每个迭代器都需要在每次成功调用之前保持一些状态,这样才知道它的位置以及如何进入下一步位置

2.4 用closure方式保持状态

一个closure就是一种可以访问外部嵌套环境的局部变量的函数,这些变量可以用在成功调用之后保持状态值,从而closure可以记住它在一次遍历后的位置。一个closure结构通常涉及两个函数,closure自身和用于创建该closure的工厂函数

下图的values就是一个工厂函数,当我们每次调用它的时候都会新建一个closure,这个closure就会将它的状态保存到外部变量i和t中,此时i和t因为closure,生命期延长,在函数结束后不会立马消失。所以每当调用values时,都会从列表t返回下一个值,直到最后一个元素返回后,迭代器返回nil,至此迭代结束。


closure
2.5 用泛型for保持状态

它和上面的closure相比,效率提高了许多,因为不需要每一次调用的时候都去创建一个新的closure。
泛型for在循环过程中保存了三个值:迭代器函数、恒定变量、控制变量

泛型for
下图k,v便是变量列表,也就是上图的var-list。变量列表的第一元素为"控制变量",循环过程中该值不会为nil,当它为nil时,循环就结束了。
2
我们看一下下面的泛型for实例,ipairs2也就是我们的表达式的原型,它返回迭代器函数、恒定对象、调用iter函数为其传入的初始值。迭代器iter返回值会赋予变量列表中的变量,如图为i,v赋给k,v,如果返回值i为nil,那么循环终止。
泛型for实例
2.6 无状态的迭代器

无状态迭代器是不保留任何状态的迭代器,避免创建闭包花费额外的代价。其实上面我们使用的ipairs2就是有一个无状态的迭代器。
下面调用square的流程就是square(3,0),square(3,1),square(3,2),它将3作为恒定状态,0作为迭代器函数的初始值。

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
2.7 多状态的迭代器

当我们迭代器需要保存多个状态时,泛型for就不适用了,因为泛型for只提供一个恒定状态和控制变量用于状态的保存。
有两种方法可以实现多状态迭代器:closure、将所需状态打包为一个table

相关文章

  • lua学习之迭代器与泛型for第一篇

    迭代器与泛型 for 1 迭代器与 closure 「迭代器」是一种可以遍历一种集合中的所有元素的机制 在 lua...

  • Lua迭代器与closure

    预备知识:lua函数是一种First-Class Value,即它与传统的变量并没有什么区别。它可以存储到变量中、...

  • lua学习之迭代器与泛型 for 第三篇

    迭代器与泛型 for 3 具有复杂状态的迭代器 使用 closure 可以保存迭代器所需保存的所有状态 也可以将迭...

  • Lua学习笔记(6)——迭代器与泛型for

    迭代器与closure 1.迭代器,就是一种可以遍历(iterate over)一种集合中所有元素的机制,它通常便...

  • lua入门笔记 目录

    lua的中文API lua入门笔记1 类型 表达式 语句 函数lua入门笔记2 深入函数 深入函数 迭代器与泛型f...

  • Lua语言学习教程

    lua闭包 函数尾调用 迭代器

  • Lua 迭代器

    https://www.cnblogs.com/Richard-Core/p/4343635.html先放个入口网...

  • Lua 迭代器

    迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确...

  • lua迭代器

    在这段代码中,匿名函数访问了一个“非局部的变量”i,改变两用于保持一个计数器。出刊上去,由于创建变量i的函数(de...

  • Lua closure

    前言# “closure”,一个之前我从没见过的词出现在了lua的编程世界中,lua将其解释为闭包,它具有着这种特...

网友评论

      本文标题:Lua迭代器与closure

      本文链接:https://www.haomeiwen.com/subject/zlemyftx.html