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日内与变化吧联系。
- 赞助本站
- 微信扫一扫
-
- 加入Q群
- QQ扫一扫
-
评论