方法

闭包

预计阅读时间1 分 4 views

前言

Go 闭包是一种嵌套函数,它允许我们在外层函数结束后仍然访问外层函数的变量。在深入学习闭包之前,我们先回顾一下以下概念:

  1. 嵌套函数(Nested Functions)
  2. 返回函数(Returning a function)

作用

闭包允许函数访问其外部函数的变量,即使外层函数已经执行完毕。这种特性使得在许多编程场景中,特别是在需要维护状态或进行数据隔离时,闭包非常有用。

使用场景

  1. 维护状态:在函数内部维护和操作状态,而不需要使用全局变量。
  2. 数据隔离:创建独立的状态实例,避免数据之间的干扰。
  3. 延迟执行:将函数和其相关的上下文一起传递,从而实现延迟执行或回调。

示例

示例 1:嵌套函数

package main
import "fmt"

// 外层函数
func greet(name string) {
  // 内层函数
  var displayName = func() {
    fmt.Println("你好", name)
  }

  // 调用内层函数
  displayName()
}

func main() {
  // 调用外层函数
  greet("John")  // 你好 John
}

在上述示例中,我们在 greet() 函数内部创建了一个匿名函数 displayName。这个内层函数可以访问 greet() 函数的参数 name,并在调用时打印它。

示例 2:返回函数

package main
import "fmt"

func greet() func() {
  return func() {
    fmt.Println("你好 John")
  }
}

func main() {
  g1 := greet()
  g1()
}

在这个示例中,greet() 函数返回一个匿名函数。我们将这个返回的函数赋值给变量 g1,然后调用 g1() 来执行这个匿名函数,输出 “你好 John”。

示例 3:闭包

package main
import "fmt"

// 外层函数
func greet() func() string {
  // 定义外层函数的变量
  name := "John"

  // 返回嵌套的匿名函数
  return func() string {
    name = "Hi " + name
    return name
  }
}

func main() {
  // 调用外层函数
  message := greet()

  // 调用内层函数
  fmt.Println(message())
}

输出

Hi John

在这个示例中,greet() 函数返回一个匿名函数,这个匿名函数可以访问并修改 greet() 函数中的 name 变量。即使 greet() 函数已经结束,返回的匿名函数仍然能够访问 name 变量,表现出闭包的特性。

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

package main
import "fmt"

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

  // 返回内层函数
  return func() int {
    num = num + 2
    return num
  }
}

func main() {
  // 调用外层函数
  odd := calculate()

  // 调用内层函数
  fmt.Println(odd())
  fmt.Println(odd())
  fmt.Println(odd())

  // 再次调用外层函数
  odd2 := calculate()
  fmt.Println(odd2())
}

输出

3
5
7
3

在这个示例中,calculate() 函数返回一个闭包,该闭包可以访问并修改 num 变量。每次调用 odd() 时,都会返回一个递增的奇数。当我们再次调用 calculate() 并赋值给 odd2 时,会返回一个新的闭包,这个闭包的 num 从 1 开始。

闭包帮助数据隔离

正如我们在前面的示例中看到的,每次调用外层函数时,都会返回一个新的闭包。每个返回的闭包都是独立的,彼此之间不会互相影响。这种特性使得我们可以在不同的闭包实例中进行数据隔离。

示例 5:数据隔离

package main
import "fmt"

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

  // 内层函数
  return func() int {
    number++
    return number
  }
}

func main() {
  // 返回一个闭包
  num1 := displayNumbers()

  fmt.Println(num1())
  fmt.Println(num1())
  fmt.Println(num1())

  // 返回一个新的闭包
  num2 := displayNumbers()
  fmt.Println(num2())
  fmt.Println(num2())
}

输出

1
2
3
1
2

在这个示例中,displayNumbers() 函数返回一个匿名函数,该匿名函数会将 number 变量递增。在 main() 函数中,我们分别调用了 num1()num2(),每个闭包都是独立的,因此它们的 number 变量不会互相干扰。

结语

闭包在 Go 中提供了强大的功能,允许我们在函数内部维护状态并实现数据隔离。通过理解和利用闭包,我们可以编写更灵活、可维护的代码。

Leave a Comment

分享此文档

闭包

或复制链接

内容