循序渐进:闭包实现斐波那契数列生成器

举报
码乐 发表于 2025/04/20 10:02:17 2025/04/20
【摘要】 1 简介什么是 Golang 中的闭包?当 Go 中的匿名函数可以访问其周围环境时,就会发生闭包。然后它可以保持自己的独特状态。然后,当我们创建函数的新实例时,之前实例的状态将是独立的。这将为函数创建一个新属性,以了解其周围环境。此属性称为 闭包closure 属性。 2 变量的范围匿名函数,嵌套函数 和 返回函数都可以访问局部块变量,如果不使用局部变量隔离数据,那么就使用全局变量(pa...

1 简介

  • 什么是 Golang 中的闭包?

当 Go 中的匿名函数可以访问其周围环境时,就会发生闭包。然后它可以保持自己的独特状态。
然后,当我们创建函数的新实例时,之前实例的状态将是独立的。

这将为函数创建一个新属性,以了解其周围环境。此属性称为 闭包closure 属性。

image.png

2 变量的范围

匿名函数,嵌套函数 和 返回函数都可以访问局部块变量,如果不使用局部变量隔离数据,那么就使用全局变量(package var)。

var x = 0
func increment() int {
    x++
    return x
}

func main() {
    fmt.Println(increment())
    fmt.Println(increment())
}

全局变量 x 未作为参数传递给匿名函数,但该函数可以访问它。

在这个例子中,有一个小问题,因为将在package中定义的任何其他函数都可以访问全局变量 x,并且它可以在不调用 increment 函数的情况下更改它。

而闭包还提供了另一个方面,即数据隔离,我们来了解它。

  func main() {
      x := 42
      fmt.Println(x)
      {
          fmt.Println(x)
          y := "功劳属于在擂台上的人。"
          fmt.Println(y)
      }
      // fmt.Println(y) // outside scope of y
  }

可以看到,我们也可以直接在main函数使用匿名函数,如果要在外部函数使用 闭包内部的变量就会报错。

3 匿名函数和嵌套函数

  • 嵌套函数

当我们在函数中创建另一个函数时,这称之为嵌套函数,以下main函数中通过创建匿名函数访问main函数变量x。

可以直接在函数中创建内部函数并且立即调用它。如此在另一个函数中创建一个函数。这称为嵌套函数。例如

	package main
	import "fmt"

	// outer function
	func Hello(name string) {

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

	}

	func main() {

	  // call outer function
	  Hello("Frank")  // Hi Frank

	}

在该示例中,我们在函数Hello内部创建了一个匿名函数displayName = func(){…},
在这里displayName它是一个嵌套函数。嵌套函数displayName的工作方式与普通函数类似。它在函数Hello内部。

这里 是一个嵌套函数。嵌套函数的工作方式与普通函数类似。它在函数 var displayName = func() {…}displayName()

4 返回匿名函数

同样的,我们可以设置匿名函数为外部函数的返回值,也就是可以创建一个返回匿名函数的函数

	package main
	import "fmt"

	func Hello() func() {
	  return func() {
	    fmt.Println("Hi Frank")
	  }
	}

	func main() {
	  h1 := Hello()
	  h1()
	}

输出

	Hi Frank

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

	func Hello() func() {...}

此处,大括号之前表示该函数返回另一个函数。func()

此外,如果你查看这个函数的 return 语句,我们可以看到该函数正在返回一个函数。

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

	h1 := Hello()

在这里,返回的函数现在被分配给变量。因此,执行嵌套的匿名函数。

5 闭包实现斐波那契数列输出

那么如何使用闭包打印斐波那契数列,同时隔离数据呢?

package main
import "fmt"

func fib() func() int {
	a := 1
	f := 0
	// returns inner function
	return func() int {
		f, a = a, f+a
		return f
	}
}

func main() {

	// call the outer function
	fdd := fib()
	// call the inner function
	for i := 0; i < 10; i++ {
		fmt.Println("f :", fdd())
	}

	// call the outer function again
	fdd2 := fib()
	fmt.Println(fdd2())

}

此代码执行外部函数并返回 斐波那契数的闭包。
这就是为什么我们可以在完成外部函数fib后, 可以连续通过fdd 访问 f 的变量。
而再次调用外部fib函数后,有fdd2 := fib(),重新得到1

在上面的示例中,该fib()函数返回一个匿名函数,

		return func() int {
			f, a = a, f+a
			return f
		}

该函数将计算原有的变量 a和f,每次调用该匿名函数都将a的值赋予f,并修改其函数内部的变量a,然后并返回f。
这表明闭包数据是彼此隔离的。

6 小结

每次调用闭包外部函数时都会返回一个新的闭包。在这里,每个返回的闭包都是彼此独立的,并且一个闭包的更改不会影响另一个闭包。

这有助于我们在彼此隔离的情况下处理多个数据。比如让我们看前面这个斐波那契数列的例子。

在需要数据隔离的地方,该闭包属性被广泛使用。它提供的数据状态使它们在这方面提供了极大的帮助。当我们想创建一个状态封装的函数时,我们使用闭包来实现。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。