码迷,mamicode.com
首页 > 其他好文 > 详细

lua的闭包

时间:2014-12-19 23:21:40      阅读:217      评论:0      收藏:0      [点我收藏+]

标签:

http://blog.csdn.net/ym012/article/details/7208750

在函数体中仍然能定义函数。假设函数f2定义在函数f1中,那么就称f2为f1的内嵌(inner)函数,f1为f2的外包(enclosing)函数

内嵌函数能访问外包函数已创建的所有局部变量,这种特性便是所谓的词法定界(lexical scoping)

    function f1(n)  
       -- 函数参数也是局部变量  
      
      
       local function f2()  
          print(n) -- 引用外包函数的局部变量  
       end  
       return f2  
    end  
      
      
    g1 = f1(1979)  
    g1() -- 打印出1979  
    g2 = f1(500)  
    g2() -- 打印出500  

 

可为什么g2和g1的函数体相同(都是f1的内嵌函数f2的函数体),但打印值不同?这就涉及到一个相当重要的概念——闭包(closure)。事实 上,Lua编译一个函数时,会为他生成一个原型(prototype),其中包含了函数体对应的虚拟机指令、函数用到的常量值(数,文本字符串等等)和一 些调试信息。在运行时,每当Lua执行一个形如function...end 这样的表达式时,他就会创建一个新的数据对象,其中包含了相应函数原型的引用、环境(environment,用来查找全局变量的表)的引用及一个由所有 upvalue引用组成的数组,而这个数据对象就称为闭包。由此可见,函数是编译期概念,是静态的,而闭包是运行期概念,是动态的。g1和g2的值严格来 说不是函数而是闭包,并且是两个不相同的闭包,而每个闭包能保有自己的upvalue值,所以g1和g2打印出的结果当然就不相同了。

 

    function f1(n)  
       local function f2()  
          print(n)  
       end  
       n = n + 10  
       return f2  
    end  
      
      
    g1 = f1(1979)  
    g1() -- 打印出1989  

 内嵌函数定义在n = n + 10这条语句之前,可为什么g1()打印出的却是1989?upvalue实际是局部变量,而局部变量是保存在函数堆栈框架上(stack frame)的,所以只要upvalue还没有离开自己的作用域,他就一直生存在函数堆栈上。这种情况下,闭包将通过指向堆栈上的upvalue的引用来 访问他们,一旦upvalue即将离开自己的作用域(这也意味着他马上要从堆栈中消失),闭包就会为他分配空间并保存当前的值,以后便可通过指向新分配空 间的引用来访问该upvalue。当执行到f1(1979)的n = n + 10时,闭包已创建了,不过n并没有离开作用域,所以闭包仍然引用堆栈上的n,当return f2完成时,n即将结束生命,此时闭包便将n(已是1989了)复制到自己管理的空间中以便将来访问,但是栈上的变量在被写到新空间之前首先被再次写数据——n=n+10

如果上面代码把f2的local去掉,改成:

    function f1(n)
	    function f2()
          print(n)
       end
       n = n + 10
       return f2
    end


    g1 = f1(1979)
    g1() -- 打印出1989
    f2()--打印1989,因为f2是闭包,内部存有自己的n

 

pvalue还能为闭包之间提供一种数据共享的机制。试看下例:

 

    function Create(n)  
       local function foo1()  
          print(n)  
       end  
       local function foo2()  
          n = n + 10  
       end  
       return foo1,foo2  
    end  
      
    f1,f2 = Create(1979)  
    f1() -- 打印1979  
    f2()  
    f1() -- 打印1989  
    f2()  
    f1() -- 打印1999  

 f1,f2这两个闭包的原型分别是Create中的内嵌函数foo1和foo2,而foo1和foo2引用的upvalue是同一个,即Create的局 部变量n。前面已说过,执行完Create调用后,闭包会把堆栈上n的值复制出来,那么是否f1和f2就分别拥有一个n的拷贝呢?其实不然,当Lua发现 两个闭包的upvalue指向的是当前堆栈上的相同变量时,会聪明地只生成一个拷贝,然后让这两个闭包共享该拷贝,这样任一个闭包对该upvalue进行 修改都会被另一个探知。上述例子非常清晰地说明了这点:每次调用f2都将upvalue的值增加了10,随后f1将更新后的值打印出来。upvalue的 这种语义非常有价值,他使得闭包之间能不依赖全局变量进行通讯,从而使代码的可靠性大大提高

 

lua的闭包

标签:

原文地址:http://www.cnblogs.com/notlate/p/4174808.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!