闭包问题


什么是闭包

参考闭包wikipedia

怎样产生闭包

闭包可以让一个函数和一组变量产生关系,让这些变量的生命周期保持持久性。
变量可以是在闭包内部声明,也可以引用外部变量,例如:

// 在函数内部创建变量
func incr() func() int {
    var x int  
    return func() int {
        x++ 
        return x 
    } 
}

// 在函数外面创建变量
var x int 
func incr() func() int { 
    return func() int {
        x++ 
        return x 
    } 
}

在函数内部创建变量可以对外部进行隐藏,在外部声明变量可以在任意点修改。
闭包特点是:函数内部有引用外部变量,且有延迟执行的特点。
在golang中比较常见的就是遍历元素,启动一个协程去执行,例如:

for i := range data {
    go func() {
        fmt.Println(i)
    }()
}

为了防止执行时i的值相同,需要做一些出,例如:

for i := range data {
    i := i
    go func() {
        fmt.Println(i)
    }()
}

// 或者
for i := range data {
    go func(i int) {
        fmt.Println(i)
    }(i)
}

闭包的用处

闭包最大的用处是利用延迟执行特性,进行一些操作。

go函数

启动定时任务,且可控制关闭它,可以使用闭包:

func startTicker(dur time.Duration) func() {
    ticker := time.NewTicker(dur)
    go func() {
       for range ticker.C {
            // do something
        }
    }()
    return ticker.Stop
}

执行代码

defer函数

常用模式还是在defer中使用闭包,而且defer+return的组合经常会让人摸不清头脑。

// 1.
func increaseA() int {
    var i int
    defer func() {
        i++
    }()
    return i
}

// 2.
func increaseB() (r int) {
    defer func() {
        r++
    }()
    return r
}

defer中的函数将会在return后延迟执行,即先会确定返回值再执行defer函数。
这样会导致increaseA函数返回时拷贝i值作为返回值,原有的i去执行defer函数,并不会影响返回值。
而increaseB函数返回的是预先定义好的返回时的地址是确定的,这样defer函数改变的还是预先定义的r值。

参考文献

  1. 闭包wikipedia
  2. 5 年 Gopher 都不知道的 defer 细节,你别再掉进坑里!

文章作者: djaigo
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 djaigo !
评论
  目录