Go 闭包

Go 闭包是一个嵌套函数,它允许我们在外部函数关闭后仍然访问外部函数的变量。

在学习闭包之前,让我们先回顾一下以下概念

  • 嵌套函数
  • 返回函数

Golang 中的嵌套函数

在 Go 中,我们可以在另一个函数内部创建一个函数。这被称为嵌套函数。例如,

package main
import "fmt"

// outer function
func greet(name string) {

// inner function var displayName = func() { fmt.Println("Hi", name) }
// call inner function displayName() } func main() { // call outer function greet("John") // Hi John }

在上面的示例中,我们在 greet() 函数内部创建了一个匿名函数

这里,var displayName = func() {...} 是一个嵌套函数。嵌套函数的工作方式与普通函数类似。当在 greet() 函数内部调用 displayName() 时,它就会执行。


在 Go 中返回函数

我们可以创建一个返回匿名函数的函数。例如,

package main
import "fmt"

func greet() func() {

return func() { fmt.Println("Hi John") }
} func main() { g1 := greet() g1() }

输出

Hi John

在上面的示例中,我们创建了 greet() 函数。

func greet() func() {...}

这里,花括号之前的 func() 表示该函数返回另一个函数。

另外,如果你查看该函数的 return 语句,可以看到该函数返回了一个函数。

main() 中,我们调用 greet() 函数。

g1 := greet()

这里,返回的函数现在被赋给了 g1 变量。因此,g1() 执行嵌套的匿名函数。


Go 闭包

正如我们已经讨论过的,闭包是一个嵌套函数,它帮助我们在外部函数关闭后仍然访问外部函数的变量。让我们看一个例子。

package main
import "fmt"

// outer function
func greet() func() string {

  // variable defined outside the inner function
  name := "John"
  
// return a nested anonymous function return func() string { name = "Hi " + name return name }
} func main() { // call the outer function message := greet()
// call the inner function fmt.Println(message())
}

输出

Hi John

在上面的示例中,我们创建了一个名为 greet() 的函数,它返回一个嵌套的匿名函数。

这里,当我们从 main() 调用函数时。

message := greet()

返回的函数现在被赋值给 message 变量。

此时,外部函数的执行已完成,因此 name 变量应该被销毁。但是,当我们使用

fmt.Println(message())

调用匿名函数时,我们可以访问外部函数的 name 变量。

这是可能的,因为嵌套函数现在充当了一个闭包,它在外部函数执行后仍然将外部作用域变量封闭在其作用域内。

让我们看另一个例子来使这个概念更清楚。


示例:使用 Golang 闭包打印奇数

package main
import "fmt"

func calculate() func() int {
  num := 1

// returns inner function return func() int { num = num + 2 return num }
} func main() { // call the outer function odd := calculate()
// call the inner function fmt.Println(odd()) fmt.Println(odd()) fmt.Println(odd())
// call the outer function again odd2 := calculate()
fmt.Println(odd2())
}

输出

3
5
7
3

在上面的例子中:

odd := calculate()

此代码执行外部函数 calculate() 并返回一个用于奇数的闭包。这就是为什么我们可以在外部函数完成后仍然访问 calculate()num 变量。

再次,当我们使用

odd2 := calculate()

调用外部函数时,会返回一个新的闭包。因此,当我们调用 odd2() 时,我们再次得到 3


闭包有助于数据隔离

正如我们在前面的例子中看到的,每次调用外部函数时都会返回一个新的闭包。这里,每个返回的闭包都是相互独立的,一个闭包的更改不会影响另一个。

这有助于我们处理多个数据,并且彼此隔离。让我们看一个例子。

package main
import "fmt"

func displayNumbers() func() int {
  number := 0

// inner function return func() int { number++ return number }
} func main() { // returns a closure num1 := displayNumbers() fmt.Println(num1()) fmt.Println(num1()) fmt.Println(num1()) // returns a new closure num2 := displayNumbers() fmt.Println(num2()) fmt.Println(num2()) }

输出

1
2
3
1
2

在上面的示例中,displayNumbers() 函数返回一个匿名函数,该函数将 number 增加 1

return func() int {
  number++
  return number
}

main() 函数中,我们将函数调用赋值给 num1num2 变量。

这里,我们首先通过 num1() 调用闭包函数。在这种情况下,我们得到输出 123

再次,我们通过 num2() 调用它。在这种情况下,number 变量的值不是从 3 开始;而是再次从 1 开始。

这表明从 displayNumbers() 返回的闭包是相互隔离的。

你觉得这篇文章有帮助吗?

我们的高级学习平台,凭借十多年的经验和数千条反馈创建。

以前所未有的方式学习和提高您的编程技能。

试用 Programiz PRO
  • 交互式课程
  • 证书
  • AI 帮助
  • 2000+ 挑战