Golang的闭包和匿名函数

发布时间 2023-12-16 13:48:58作者: abce

Golang语言支持匿名函数,这些匿名函数也被称为闭包。匿名函数是一种特殊类型的函数,它没有名称,而闭包可以看作是一种特殊类型的匿名函数,尽管在实践中有微小的区别。

 

Golang 中的匿名函数
匿名函数也可以称为字面函数、lambda 函数或闭包。闭包的概念源于 lambda 计算中表达式的数学评估。从技术上讲,匿名函数和闭包之间有一个微妙的区别:匿名函数是一个没有名称的函数,而闭包是一个函数的实例。然而,要在 Golang 中实际实现闭包,编写匿名函数是关键。

 

如何创建闭包
通过匿名函数,我们可以在任何表达式中编写表示函数值的字面函数。其语法与命名的函数(常规函数)非常相似,只是在 func 关键字之后没有名称。因此,如果 Go 开发人员不想给函数命名,那么我们可以创建匿名函数。

以下是在 Go 中创建闭包的语法和示例代码:

func (a, b int){ return a+b }

请注意,这种函数不能单独编写,因此在赋值时要声明一个变量,如:

sum := func(a, b int) int { return a + b }
fmt.Println(sum(1, 2))

函数的调用方式为 sum(1,2)。

也可以在定义时直接调用,如下所示:

sum := func(a, b int) int { return a + b }(1, 2)
fmt.Println(sum)

下面是另一个求整数之和的示例
--在这个代码示例中,我们可以将匿名函数编写如下:

	func() {
		sum := 0
		for i := 0; i < 100; i++ {
			sum += i
		}
	}()


func 关键字后的第一个括号 () 是参数列表,闭包没有名称。闭包的主体由大括号 {} 组成,最后一对小括号 () 表示函数调用。

 

闭包如何返回值
闭包或匿名函数可以创建带参数或不带参数的函数,但我们能从这样的函数中返回值吗?
下面是一个如何从 Go 中的闭包返回值的示例。让我们编写一个函数,每次调用都返回下一个斐波那契数字:

package main

import "fmt"

func fibonacci() func() int {
	a, b := -1, 1
	return func() int {
		a, b = b, a+b
		return b
	}
}

func main() {
	fibo := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(fibo())
	}
}

 

函数返回另外一个函数
已声明的局部变量的作用域有限,只存在于声明该变量的程序块或函数中。
当变量失去作用域时,就会被刷出内存。不过,在闭包的帮助下,即使在执行程序离开代码块后,局部变量仍有可能继续存在。我们可以使用 Go 闭包编写一个返回另一个函数的函数。下面是一个例子:

func square() func(num int) int {
	return func(num int) int {
		return num * num
	}
}

func mul(n1 int) func(n2 int) int {
	return func(n2 int) int {
		return n1 * n2
	}
}

func main() {

	// make an square function, give it a name f2, and call it:
	f2 := square()
	fmt.Printf("Call square for 3 gives: %v\n", f2(3))
	// make a special mul function, n1 gets value 3:
	f3 := mul(3)
	fmt.Printf("The result is: %v\n", f3(3))
}

 

将匿名函数作为参数传递
下面的示例程序说明了如何在 Go 中将匿名函数作为参数传递给另一个函数。同时请注意,匿名函数在变量上闭包,形成一个闭包:

package main

import (
	"fmt"
	"math/rand"
	"time"
)

func xyValues(f func(max int) (int, int)) {
	x, y := f(35)
	fmt.Println(x, y)
	x, y = f(50)
	fmt.Println(x, y)
}

func main() {
	fn := func(max int) (int, int) {
		r := rand.New(rand.NewSource(time.Now().UnixNano()))
		x_axis := r.Intn(max)
		y_axis := r.Intn(max)
		return x_axis, y_axis
	}

	xyValues(fn)
	x, y := fn(20)
	fmt.Println(x, y)
}

在上述代码示例中,匿名函数是在主函数中声明的。它只是在作为函数参数传入的最大值范围内,为 x_axis 和 y_axis 生成两个随机整数,并返回。
匿名函数被赋值给变量 fn,并将函数值传递给另一个名为 xyValues 的函数。xyValues 函数反过来接收一个函数作为参数,即 fn 函数参数。

有几点需要注意:在 main 中,匿名函数的值有两个用途:
·将函数值作为参数传递,调用 xyValues 函数。
·通过提供一个值作为参数,直接调用函数值。