概念

闭包是由函数及其相关引用环境组合而成的实体,一般提供通过在匿名函数中引用外部函数的局部变量或包全局变量构成。
即:闭包 = 函数 + 引用环境
闭包对闭包外的环境引入是直接引用,编译器检测到闭包,会将闭包引用的外部变量分配到栈上。
如果函数返回的闭包引用了该函数的局部变量(参数或函数内部变量):

  1. 多次调用该函数,返回的多个闭包所引用的外部变量是多个副本,原因是每次调用函数都会为局部变量分配内存
  2. 用一个闭包函数多次,如果该闭包修改了其引用的外部变量,则每一次调用该闭包对该外部变量都有影响,因为闭包函数共享外部引用
package main
func test(a int) func(i int) int{
    return func(i int) int{
        println(&a,a)
        a = a + i
        return a
    }
}
func main(){
    //f,g引用的外部的闭包环境包括本次函数调用的形参a的值1
    f := test(1)
    g := test(1)
    //多次调用的f,g引用的a为同一个a
    println(f(1))
    println(f(1))
    println(g(1))
    println(g(1))
}
//output
0x103100c0 1
2
0x103100c0 2
3
0x103100c4 1
2
0x103100c4 2
3

建议

如果一个函数调用返回的闭包引用修改了全局变量,则每次调用都会影响全局变量。
如果函数返回的闭包引用的是全局变量 a ,则多次调用该函数的返回的多个闭包引用的都是同一个 a 。同理,调用一个闭包多次引用一个 a 。此时如果闭包中修改了 a 值的逻辑,则每次闭包调用都会影响全局变量 a 的值。使用闭包是为了减少全局变量,所以闭包引用 全局变量不是好的编程方式。

 package main
 var a = 0
 func test() func(i int) int{
     return func(i int) int{
         println(&a,a)
         a = a + i
         return a
     }
 }
 func main(){
     f := test()
     g := test()
     //此时f,g引用的闭包环境中的a是同一个
     println(f(1))
     println(g(1))
     println(g(1))
     println(g(1))
     println(f(1))
 }
//output
 0xa9e9c 0
 1
 0xa9e9c 1
 2
 0xa9e9c 2
 3
 0xa9e9c 3
 4
 0xa9e9c 4
 5

价值

闭包最初的目的是减少全局变量,在函数调用的过程中隐式的传递共享变量,有其有用的一面;但是这种隐瞒的共享变量的方式带来的 坏处是不够直接,不够清晰,除非是非常有价值的地方,一般不会使用闭包。
对象是附有行为的数据,而闭包是附有数据的行为,类在定义是就已经显式的集中定义了行为,但是闭包中的数据没有显式的集中 声明的地方,这种数据和行为耦合的模型不是一种推荐的编程模型,闭包只是锦上添花的东西,不是必不可少的。
——《Go 语言核心编程》

其他要说的

什么是闭包?闭包的优缺点?:https://www.cnblogs.com/cxying93/p/6103375.html

标签: Golang

添加新评论