闭包函数

* 本页面主要介绍Go语言闭包函数的相关内容。

相信“闭包”大家都听过,但到底什么是闭包,未必你就能够清晰的讲出来!那么这一节,就是解答这个疑问的。

一、何为闭包?

闭包(Closure)是由函数及其相关引用环境组合而成的实体(即:闭包=函数+引用环境)。或者另外一种比较常见的说法:闭包,是引用了自由变量的函数。

“官方定义”:

所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

支持闭包的编程语言非常多,目前在JavaScript、Go、PHP、Scala、Scheme、Common Lisp、Smalltalk、Groovy、Ruby、 Python、Lua、objective c、Swift 以及Java8以上等语言中都能找到对闭包不同程度的支持。

看个最常见的闭包例子(JavaScript):

  

上面的代码创建了闭包,a函数返回了b函数,c指向了函数b,执行c()会显示i的值,所以,当函数a内的函数b被外面的变量引用时,就创建了一个闭包。因为闭包的存在,。a中的变量i始终存在,因为闭包使得垃圾回收机制GC不会收回a函数占用的资源。

c()跟c2()引用的是不同的环境,即引用的i变量不是一个。函数a()每进入一次,就形成了一个新的环境,对应的闭包中,函数都是同一个函数,环境却是引用不同的环境。

二、GO的闭包

Go语言当然也是支持闭包的,还是以上面的例子为例,改成Go语言版本的:

  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() //不会输出i
  }

  //输出结果
  1
  2
  3

闭包复制的是原对象指针,这就很容易解释延迟引用现象。看下面的示例:

  x := 1
  f := func() {
      println(x)
  }
  x = 2
  x = 3
  f() // 3

因为闭包对外层词法域变量是引用的,所以这段代码会输出 3。可以想象 f 中保存着 x 的地址,它使用 x 时会直接解引用,所以 x 的值改变了会导致 f 解引用得到的值也会改变。

关于循环闭包引用的时候有一个比较常见的“坑”,大家可以移步这里详细了解: 代码块和作用域 Part 3。

Go闭包的内容就总结到这里,你都Get了吧?


* 本页内容参考以下数据源:

  • 《Go程序设计语言》
  • https://studygolang.com/articles/29013

凯冰科技 · 代码改变世界,技术改变生活
Next Page→