8.2.10 尾递归tailrec

Kotlin 支持一种称为尾递归的函数式编程风格。 这允许一些通常用循环写的算法改用递归函数来写,而无堆栈溢出的风险。 当一个函数用 tailrec 修饰符标记并满足所需的形式时,编译器会优化该递归,生成一个快速而高效的基于循环的版本。

  1. tailrec fun findFixPoint(x: Double = 1.0): Double
  2. = if (x == Math.cos(x)) x else findFixPoint(Math.cos(x)) // 函数必须将其自身调用作为它执行的最后一个操作

这段代码计算余弦的不动点(fixpoint of cosine),这是一个数学常数。 它只是重复地从 1.0 开始调用 Math.cos,直到结果不再改变,产生0.7390851332151607的结果。最终代码相当于这种更传统风格的代码:

  1. private fun findFixPoint(): Double {
  2. var x = 1.0
  3. while (true) {
  4. val y = Math.cos(x)
  5. if (x == y) return y
  6. x = y
  7. }
  8. }

要符合 tailrec 修饰符的条件的话,函数必须将其自身调用作为它执行的最后一个操作。在递归调用后有更多代码时,不能使用尾递归,并且不能用在 try/catch/finally 块中。尾部递归在 JVM 后端中支持。

Kotlin 还为集合类引入了许多扩展函数。例如,使用 map() 和 filter() 函数可以流畅地操纵数据,具体的函数的使用以及示例我们已经在 集合类 章节中介绍。