长安链 DApp 开发必学 Go 06

86 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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比较难处理,上面给出了一种实现方式,不知道有没有朋友有更优雅的实现,欢迎评论区分享~

好,我们下一章见!