开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天,点击查看活动详情
本文已参与「开源摘星计划」,欢迎正在阅读的你加入。活动链接:github.com/weopenproje…
上一章介绍完了数据结构中的大哥大——哈希表 map。这一章,继续深入,讲讲函数成为“一等公民”那些事。
这个概念专业的说法是 First-class Function,翻译为“头等函数”,也标志着函数可以像其他变量、常量一样,可以作为其他函数的参数、返回值,可以赋值给变量,也可以存储在数据结构中。
在讲清楚这样设计有什么好处之前,先来看看它在 go 中怎样使用:
package main
import (
"fmt"
"math"
)
// 定义一个 compute 函数,它接收一个函数作为参数。这个函数接收两个 float64 类型的参数,返回 float64 类型的参数。
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
// 定义一个变量,它的值是一个函数,准确的说是一个匿名函数。
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(5, 12))
fmt.Println(compute(hypot))
fmt.Println(compute(math.Pow))
}
可以看到,go 语言写起来依然很简洁流畅。而且有个很直观的感受,就是灵活。这就是函数升级为“一等公民”的好处,它提供了更高的编程灵活性,让程序员更加自由地实现逻辑。
例如,可以开发出“高阶函数”,写出更有可读性的代码。也可以实现一个编程界很有名、应用很广的功能——闭包:
package main
import "fmt"
func adder() func(int) int {
sum := 0
// 返回一个匿名函数,这个函数使用函数内的局部变量 sum 来实现累加
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder() // 分别获得两个闭包
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
如上,通过返回“一等公民”函数,构造闭包,从而保存了匿名函数的上下文。根据这个特性,可以很轻松的给函数增加一些额外的执行逻辑,而且,让代码的可读性大大提高,逻辑更加清晰易懂。
ok,让我们来实际写个代码练一练手,实现一个打印斐波那契数列的闭包:
package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
a := -1
b := 0
return func() int {
if a == -1 {
a += 1 // 给 a 赋初始值 0
return 0
} else if b == 0 {
b += 1 // 给 b 赋初始值 1
return 1
} else {
temp := b // 暂存 b 的值
b += a // 更新 b = b + a
a = temp // 把 b 的前值给 a
return b
}
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
实现上述函数有个难点,就是前两个值0、1比较难处理,上面给出了一种实现方式,不知道有没有朋友有更优雅的实现,欢迎评论区分享~
好,我们下一章见!