diff --git a/README.md b/README.md index abefc60..ddf3cb2 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ ## 翻译进度 -6.4 [内置函数](eBook/06.5.md) +6.6 [递归函数](eBook/06.6.md) ## 支持本书 @@ -40,7 +40,7 @@ ## 捐助译者 -如果您觉得本书翻译确实不错,并认为译者的努力值得肯定,可以通过 [此链接](https://me.alipay.com/obahua) 为译者提供小额捐助,以资鼓励。 +如果您觉得本书翻译确实不错,并认为译者的努力值得肯定,可以通过 [此链接](http://gogs.io/donate) 为译者提供小额捐助,以资鼓励。 ## 开始阅读 diff --git a/eBook/06.6.md b/eBook/06.6.md index 96093f4..d147adc 100644 --- a/eBook/06.6.md +++ b/eBook/06.6.md @@ -1,3 +1,119 @@ # 6.6 递归函数 -143 \ No newline at end of file +当一个函数在其函数体内调用自身,则称之为递归。最经典的例子便是计算斐波那契数列,即每个数均为前两个数之和。 + +数列如下所示: + + 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, … + +下面的程序可用于生成该数列(Listing 6.13 fibonacci.go): + +```go +package main + +import "fmt" + +func main() { + result := 0 + for i := 0; i <= 10; i++ { + result = fibonacci(i) + fmt.Printf("fibonacci(%d) is: %d\n", i, result) + } +} + +func fibonacci(n int) (res int) { + if n <= 1 { + res = 1 + } else { + res = fibonacci(n-1) + fibonacci(n-2) + } + return +} +``` + +输出: + +``` +fibonacci(0) is: 1 +fibonacci(1) is: 1 +fibonacci(2) is: 2 +fibonacci(3) is: 3 +fibonacci(4) is: 5 +fibonacci(5) is: 8 +fibonacci(6) is: 13 +fibonacci(7) is: 21 +fibonacci(8) is: 34 +fibonacci(9) is: 55 +fibonacci(10) is: 89 +``` + +许多问题都可以使用优雅的递归来解决,比如说著名的快速排序算法。 + +在使用递归函数时经常会遇到的一个重要问题就是栈溢出:一般出现在大量的递归调用导致的程序栈内存分配耗尽。这个问题可以通过一个名为懒惰评估的技术解决,在 Go 语言中,我们可以使用管道(channel)和 goroutine(详见第 14.8 节)来实现。练习 14.12 也会通过这个方案来优化斐波那契数列的生成问题。 + +Go 语言中也可以使用相互调用的递归函数:多个函数之间相互调用形成闭环。因为 Go 语言编译器的特殊性,这些函数的声明顺序可以是任意的。下面这个简单的例子展示了函数 odd 和 even 之间的相互调用(Listing 6.14 mut_recurs.go): + +```go +package main + +import ( + "fmt" +) + +func main() { + fmt.Printf("%d is even: is %t\n", 16, even(16)) // 16 is even: is true + fmt.Printf("%d is odd: is %t\n", 17, odd(17)) + // 17 is odd: is true + fmt.Printf("%d is odd: is %t\n", 18, odd(18)) + // 18 is odd: is false +} + +func even(nr int) bool { + if nr == 0 { + return true + } + return odd(RevSign(nr) - 1) +} + +func odd(nr int) bool { + if nr == 0 { + return false + } + return even(RevSign(nr) - 1) +} + +func RevSign(nr int) int { + if nr < 0 { + return -nr + } + return nr +} +``` + +### 练习题 + +**练习 6.4** + +重写本节中生成斐波那契数列的程序并返回两个命名返回值(详见第 6.2 节),即数列中的位置和对应的值,例如 5 与 4,89 与 10。 + +**练习 6.5** + +使用递归函数从 10 打印到 1。 + +**练习 6.6** + +实现一个输出前 30 个整数的阶乘的程序。 + +n! 的阶乘定义为:`n! = n * (n-1)!, 0! = 1`,因此它非常适合使用递归函数来实现。 + +然后,使用命名返回值来实现这个程序的第二个版本。 + +特别注意的是,使用 int 类型最多只能计算到 12 的阶乘,因为一般情况下 int 类型的大小为 32 位,继续计算会导致溢出错误。那么,如何才能解决这个问题呢? + +最好的解决方案就是使用 big 包(详见第 9.4 节)。 + +## 链接 + +- [目录](directory.md) +- 上一节:[内置函数](06.5.md) +- 下一节:[将函数作为参数](06.7.md) \ No newline at end of file diff --git a/eBook/06.7.md b/eBook/06.7.md new file mode 100644 index 0000000..f80e6f7 --- /dev/null +++ b/eBook/06.7.md @@ -0,0 +1,3 @@ +# 6.7 将函数作为参数 + +146 \ No newline at end of file diff --git a/eBook/directory.md b/eBook/directory.md index 3b0ae01..69e376a 100644 --- a/eBook/directory.md +++ b/eBook/directory.md @@ -52,6 +52,7 @@ - 6.4 [defer 和追踪](06.4.md) - 6.5 [内置函数](06.5.md) - 6.6 [递归函数](06.6.md) + - 6.7 [将函数作为参数](06.7.md) - 第7章:数组(array)与切片(slice) - 第8章:Maps - 第9章:包(package)