学习一门新语言需要了解的基础-15 闭包

小说:小红书黑卡免费兑换码作者:顺董王更新时间:2019-03-20字数:20570

学习一门新语言需要了解的基础-15 闭包


本节内容

  • 何为闭包
  • 闭包通过指针引用环境变量
  • 闭包导致环境变量生命周期延长和堆分配
  • 闭包怎么调用的[付费阅读]
  • 闭包与数据竞争

何为闭包

$ cat test.go
package main

func test(x int) func() {
    println("test.x :", &x)
    
    return func() {
        println("closure.x :", &x, x)
    }
}

func main() {
    f := test(100)
    f()
}

闭包最常用的例子是,一个匿名函数引用了它的上下文对象x,那么我们把这种状态称之为闭包。

闭包通过指针引用环境变量

闭包严格意义上来说,由两个东西组成的,函数加上环境变量,这两个东西合起来称之为闭包。闭包我们都知道有这样一个问题,比如说有一个函数,函数内部有个环境变量x,当它返回一个匿名函数的时候,这个函数是通过指针访问环境变量x的,并不是把环境变量x复制过去,用指针引用环境变x量实际上会造成这个局部变量x在堆上分配,生命周期延长。以代码为例,test函数访问之后test代码就结束了,结束了以后它的栈帧就失效了,这样再去引用变量x的时候肯定会有问题,我们知道你不能引用地址空间已经无效的内容,所以会造成这个x从栈上逃逸到堆上。

闭包导致环境变量生命周期延长和堆分配

我们看下是否逃逸到堆上了:

$ go build -gcflags "-N -l -m" -o test test.go
./test.go:6:12: func literal escapes to heap
./test.go:6:12: func literal escapes to heap
./test.go:7:33: &x escapes to heap
./test.go:3:22: moved to heap: x #我们可以看到moved to heap:x
./test.go:4:25: test &x does not escape
./test.go:7:32: test.func1 &x does not escape

因为只有把x放到堆上时候,当我们去执行f()时候,对象才能在堆上找到,不用担心它在栈上会被覆盖掉。所以这就会造成一个问题闭包会导致它所引用的环境变量生命周期延长,原来test()函数执行结束以后x的值就失效了,现在呢?test()函数虽然执行结束了,但是x值依然存在,为什么要存在?因为当我们执行f()调用代码时候x不存在就出错了,所以x的生命周期必然延长,延长就必须从当前栈帧上逃逸到堆上,才有可能在调用时候依然有效的。

闭包怎么调用的[付费阅读]

闭包与数据竞争

闭包可能引起数据竞争,刚刚我们知道闭包是通过指针引用环境变量,比如说一个函数有个x,同时返回两个匿名函数,这两个匿名函数都引用x的情况下,他们都持有x的指针,当两个匿名函数都对x并发操作时,就会形成数据竞争效应,因为两个匿名函数都用不同线程执行时,他们同时去访问x就会引起数据竞争,理论上我们需要对它加锁处理。

$ cat race.go
package main

import "time"

func test(x int) (func(), func()) {

    // 尽管 x 不是指针,但闭包内部通过指针引用,所以
    // 也会导致数据竞争(data race)发生。

    w := func() {
            for {
                x++
            }
        }

    r := func() {
           for {
               _ = x
            }
        }

    return w, r
}

func main() {
    w, r := test(100)
    
    go w()
    go r()

    time.Sleep(time.Second * 10)
}
$ go run -race race.go #-race参数用于数据竞争检查

闭包实际上是由两个东西组成的,第一个匿名函数,第二个环境变量,合起来才叫闭包。不同的语言对闭包的处理不太一样。

当前文章:http://scycxh.com/play/owm85pzzit.html

发布时间:2019-03-20 12:27:17

拼多多黑号怎么办 返利网包括花生日记吗 美逛收益 府谷县通村公路审批 最靠谱的网赚项目 最赚钱的稳定投资 利用漏洞赚钱多少犯法 淘宝刷单软件赚钱 赚钱养家 可以赚钱的平台

95592 69053 49902 85922 25298 4522923448 15595 44482

我要说两句: (0人参与)

发布