Golang的闭包和匿名函数
2023-12-16 13:44 abce 阅读(250) 评论(0) 编辑 收藏 举报Golang语言支持匿名函数,这些匿名函数也被称为闭包。匿名函数是一种特殊类型的函数,它没有名称,而闭包可以看作是一种特殊类型的匿名函数,尽管在实践中有微小的区别。
Golang 中的匿名函数
匿名函数也可以称为字面函数、lambda 函数或闭包。闭包的概念源于 lambda 计算中表达式的数学评估。从技术上讲,匿名函数和闭包之间有一个微妙的区别:匿名函数是一个没有名称的函数,而闭包是一个函数的实例。然而,要在 Golang 中实际实现闭包,编写匿名函数是关键。
如何创建闭包
通过匿名函数,我们可以在任何表达式中编写表示函数值的字面函数。其语法与命名的函数(常规函数)非常相似,只是在 func 关键字之后没有名称。因此,如果 Go 开发人员不想给函数命名,那么我们可以创建匿名函数。
以下是在 Go 中创建闭包的语法和示例代码:
1 | func (a, b int ){ return a+b } |
请注意,这种函数不能单独编写,因此在赋值时要声明一个变量,如:
1 2 | sum := func(a, b int ) int { return a + b } fmt.Println( sum (1, 2)) |
函数的调用方式为 sum(1,2)。
也可以在定义时直接调用,如下所示:
1 2 | sum := func(a, b int ) int { return a + b }(1, 2) fmt.Println( sum ) |
下面是另一个求整数之和的示例
--在这个代码示例中,我们可以将匿名函数编写如下:
1 2 3 4 5 6 | func() { sum := 0 for i := 0; i < 100; i++ { sum += i } }() |
func 关键字后的第一个括号 () 是参数列表,闭包没有名称。闭包的主体由大括号 {} 组成,最后一对小括号 () 表示函数调用。
闭包如何返回值
闭包或匿名函数可以创建带参数或不带参数的函数,但我们能从这样的函数中返回值吗?
下面是一个如何从 Go 中的闭包返回值的示例。让我们编写一个函数,每次调用都返回下一个斐波那契数字:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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 闭包编写一个返回另一个函数的函数。下面是一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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 中将匿名函数作为参数传递给另一个函数。同时请注意,匿名函数在变量上闭包,形成一个闭包:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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 函数。
·通过提供一个值作为参数,直接调用函数值。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
2021-12-16 Oracle中有大量的sniped会话
2021-12-16 Oracle kill会话
2015-12-16 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated
2015-12-16 explicit_defaults_for_timestamp参数
2015-12-16 EBS创建相应的用户