golang 闭包

  • 闭包相当于保存了外部环境的变量的引用
    • 如果不会修改外部变量,会退化为值
    • 闭包中对外部变量的改变也会影响外部变量的值
    • 同样外部变量的改变也会影响闭包内的值
// 闭包底层实现原理
type Closure struct {
	F unitptr // 函数指针
	env *Type //使用到的外部环境变量指针;如果没有修改,则会优化为值传递
  • 编译器检测报告闭包时,会把闭包引用的外部变量分配到堆上
  • 闭包的目的之一是减少全局变量
    • 在函数调用时隐式传递共享变量
    • 但这种共享变量方式不够清晰

闭包的坑

  • 在for循环中使用闭包时,应该把迭代变量作为参数传入闭包

    • 例如for k, v := range m中的k, v, for i :=0; i < 10; i++中的i
    • 原因在于k,v,i在迭代的过程中地址不变,而是不断被重新赋值
      • 因此每次迭代闭包引用的都是同一个地址,所以都得到的是同样的值
  • 如果函数返回了一个闭包,使用该函数构造新函数并调用多次,则每次调用该新函数造成的影响是累积的

    • 因为闭包函数共享外部引用
    • 如果闭包引用了全局变量,则每次调用新函数都会影响全局变量
      • 最好不要把闭包和全局变量混合使用
func fa(a int) func(i int) int {
	return func(i int) int {
		fmt.Println(&a, a)
	    a = a + i
	    return a
    }
}

f := fa(1)
fmt.Println(f(1))
fmt.Println(f(1))

// 输出
0x1234 1
2
0x1234 2
3
  • 如果构造了多个新函数,则这些新函数之间的调用互相不影响
f := fa(1)
g := fa(1)

fmt.Println(f(1))
fmt.Println(g(1))

// 输出
0x1234 1
2
0x5678 1
2
  • 闭包+defer可能在return后改变返回值
func f() (res int) {
    defer func() {
        res++
    }
	return 0
}

fmt.Println(f()) // 输出1,而不是0

闭包的使用

  • 闭包可以用来构造工厂函数
    • 返回值为另一个函数的函数可以被称之为工厂函数
    • 这在您需要创建一系列相似的函数的时候非常有用:书写一个工厂函数而不是针对每种情况都书写一个函数
func MakeAddSuffix(suffix string) func(string) string {
	return func(name string) string {
		if !strings.HasSuffix(name, suffix) {
			return name + suffix
		}
		return name
	}
}

addBmp := MakeAddSuffix(".bmp")
addJpeg := MakeAddSuffix(".jpeg")

addBmp("file") // returns: file.bmp
addJpeg("file") // returns: file.jpeg
  • 闭包可以用来返回关闭函数
    • 关闭打开的文件,通道等
    • 调用者在关闭时不用知道内部细节
// 返回的removeFile函数可以关闭函数内打开的临时文件,即使函数返回后文件名已不可知
func createTempFile(initialData string) (io.ReadWriteSeeker, func()) {
    tmpfile, err := ioutil.TempFile("", "db")

    if err != nil {
        fmt.Printf("could not create temp file %v", err)
    }

    tmpfile.Write([]byte(initialData))

    removeFile := func() {
        os.Remove(tmpfile.Name())
    }

    return tmpfile, removeFile
}

// 调用者
 database, cleanDatabase := createTempFile(`[
            {"Name": "Cleo", "Wins": 10},
            {"Name": "Chris", "Wins": 33}]`)
 defer cleanDatabase()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值