在本教程中,您将学习如何在Golang中使用闭包。在讨论闭包之前,我们需要理解变量作用域和生命周期的概念。您将涵盖闭包的需求及其独特环境。
考虑一个函数,其中声明了一个在该函数内部可见的变量。作用域是静态的,这是我们编写的编程代码的一个特性,基于编译时;而生命周期则取决于程序执行(运行时)。
闭包是一个函数内部的函数,“捕获”外部函数的一个或多个局部变量。Golang支持嵌套函数。嵌套函数是定义在另一个函数内部的函数。
考虑下面的示例代码
func fib() func() int {
a, b := 0,1
return func() int {
a, b = b, a+b
return b
}
}
闭包涉及一个函数使用来自另一个函数作用域的变量

让我们通过上面代码的实际解释来理解
匿名函数,它没有名称。它只是一个带有某些代码的函数字面量。它使用了变量 a 和 b,但没有声明 a 和 b。请看下图

该图左侧显示函数,右侧显示闭包。假设有一个变量赋值
f:= fib
f被声明并赋值为fib,这里fib使用时没有括号,只取fib这个名称,指的是函数,而不是函数调用,这里相当于一个指向代码的指针,即它将指向函数fib
如果f作为带括号的函数被调用,即像fib()函数调用一样。f和fib是同一个东西的两个名称。这些由上图的左侧表示。
接下来在右侧,调用函数fib()并赋值给变量f。
f := fib( )
f不是一个函数,它是一个闭包。它有两部分:env 和 fp。在上面讨论的代码中,有一个匿名函数(F2),它实际上是从fib中返回的第一部分。第二部分包含了关于在哪里找到a和b的信息。因为匿名内部函数改变了a和b的值,并返回了b。
所以闭包是程序后台运行时不可见的实践。
// Anonymous functions are useful when you want to define
// a function inline without having to name it.
package main
import "fmt"
// This function `fib` returns another function, which
// we define anonymously in the body of `fib`. The
// returned function _closes over_ the variable `a & b` to
// form a closure.
func fib() func() int {
a, b := 0,1
return func() int {
a, b = b, a+b
return b
}
}
func main() {
f := fib()
for x:=f();x<100;x=f() {
fmt.Println(x); // 1 2,3,4,8,13,21,34,55,89
}
}
输出
1 2 3 5 8 13 21 34 55 89
Golang中闭包(即一个函数返回另一个函数)的需求是作用域。假设有一个函数,其中某些值被初始化给一个变量。函数只是一组要执行的指令。该函数内部的内部函数将使用外部函数初始化的值。
通过在已声明的外部函数内部声明一个匿名函数来创建闭包。该函数可以访问其周围状态并形成独特。
示例

下面的代码是一个包含i的函数f的闭包。闭包特性得到满足,匿名函数f可以直接访问i的值。
package main
import (
"fmt"
)
func main() {
i := 40
f := func() {
// has access to i
j := i - 2
fmt.Println(j)
}
f() // 38
}
输出
38
Golang支持闭包函数中可用的数据隔离特性。每当创建闭包时,其状态都是唯一的。这使得它们各自拥有自己的状态。内部变量对于每个闭包来说都是唯一的。
让我们通过一个例子来理解
package main
import "fmt"
func fib() func() int {
a, b := 0, 1
// return a closure over a & b
return func() int {
a, b = b, a+b
return b
}
}
func main(){
f , g := fib(), fib()
// f & g have their own copies of a & b
fmt.Println(f(),f(),f())
fmt.Println(g(),g(),g()) //f() , g() prints identical lines 1,2,3
}
输出
1 2 3 1 2 3