Go语言闭包函数

幸运草
幸运草
幸运草
967
文章
3
评论
2020年4月19日22:10:25 评论 154

Go语言闭包函数

基本概念

闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块内或者任何全局上下文中定义,而是在定义代码块的环境中定义。要执行的代码块(由于自由变量包含在代码块中,所以这些自由变量以及它们引用的对象没有被释放)为自由变量提供绑定的计算环境(作用域)。

闭包的价值

闭包的价值在于可以作为函数对象或者匿名函数,对于类型系统而言,这意味着不仅要表示数据还要表示代码。支持闭包的多数语言都将函数作为第一级对象,就是说这些函数可以存储到变量中作为参数传递给其他函数,最重要的是能够被函数动态创建和返回。

Go语言闭包

1、Go语言是支持闭包的,实例如下:

package main

import (
    "fmt"
)

func a() func() int {
    i := 0
    b := func() int {
        i++
        fmt.Println(i)
        return i
    }
    return b
}

func main() {
    c := a()
    c()
    c()
    c()

    a() 

    fmt.Println("-------")

    d := a()
    d()
    d()
    d()
}

运行结果:

1
2
3
-------
1
2
3

上述代码分析:

函数b嵌套在函数a内部,函数a返回函数b。

代码在执行完 c := a() 后,变量c实际上是指向了函数b(),再执行函数c()后就会显示 i 的值,第一次为1,第二次为2,第三次为3,以此类推。
其实,这段代码就创建了一个闭包。因为函数 a() 外的变量 c 引用了函数 a() 内的函数 b() ,就是说:

当函数 a() 的内部函数 b() 被函数 a() 外的一个变量引用的时候,就创建了一个闭包。
在上面的例子中,由于闭包的存在使得函数 a() 返回后,a 中的 i 始终存在,这样每次执行 c() ,i都是自加1后的值。
从上面可以看出闭包的作用就是在a()执行完并返回后,闭包使得Golang的垃圾回收机制GC不会收回 a() 所占用的资源,因为 a() 的内部函数 b() 的执行需要依赖 a() 中的变量 i 。

在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。变量的作用域仅限于包含它们的函数,因此无法从其它程序代码部分进行访问。不过,变量的生存期是可以很长,在一次函数调用期间所创建所生成的值在下次函数调用时仍然存在。正因为这一特点,闭包可以用来完成信息隐藏,并进而应用于需要状态表达的某些编程范型中。

如果 a() 返回的不是函数 b() ,情况就完全不同了。因为 a() 执行完后,b() 没有被返回给 a() 的外界,只是被 a() 所引用,而此时 a() 也只会被 b() 引 用,因此函数 a() 和 b() 互相引用但又不被外界引用,函数 a 和 函数 b 就会被GC回收。所以直接调用 a() 并没有信息输出。

c() 跟 d() 引用的是不同的环境,在调用 i++ 时修改的不是同一个 i,因此两次的输出都是1。函数 a() 每进入一次,就形成了一个新的环境,对应的闭包中,函数都是同一个函数,环境却是引用不同的环境。这和 c() 和 d() 的调用顺序都是无关的。

2、Go语言闭包复制的是原对象指针,实例如下:

package main

import "fmt"

func oldboy() func() {
    str := "oldboy"
    fmt.Printf("str (%p) = %sn", &str, str)

    return func() {
        fmt.Printf("str (%p) = %sn", &str, str)
    }
}

func main() {
    o := oldboy()
    o()
}

运行结果:

str (0xc42000e1d0) = oldboy
str (0xc42000e1d0) = oldboy

特别声明:以上文章内容仅代表作者本人观点,不代表变化吧观点或立场。如有关于作品内容、版权或其它问题请于作品发表后的30日内与变化吧联系。

转载请注明:{{title}}-变化吧
  • 赞助本站
  • 微信扫一扫
  • weinxin
  • 赞助本站
  • 支付宝扫一扫
  • weinxin
幸运草
Go语言接口规则 前端框架

Go语言接口规则

Go语言接口规则 接口是一个或多个方法签名的集合。任何类型的方法集中只要拥有该接口对应的全部方法签名。就表示它 "实现" 了该接口,无须在该类型上显式声明实现了哪个接口。对应方法,是指有相同名称、参数...
Go语言中处理 HTTP 服务器 前端框架

Go语言中处理 HTTP 服务器

1 概述 包 net/http 提供了HTTP服务器端和客户端的实现。本文说明关于服务器端的部分。 快速开始: package main import (   "log"   "net/http" )...