在Kotlin中tailrec的意义是什么?

时间:2018-08-01 16:51:57

标签: kotlin

<template> <div class="headerNav"> <transition name="fade"> <div v-if="logo" class="logo" key="1"></div> <div v-else class="logo two" key="2"></div> </transition> </div> </template> <script> export default { name: 'Navbar', components: { postFilter, }, data() { return {} }, computed: { logo() { if (this.$route.name == 'Library' || this.$route.name == 'Profile') { return false } else { return true } } } </script> 优化存在尾递归的函数。为什么编译器仍然不对其进行优化?

C编译器针对尾递归进行优化。您不必将方法标记为具有尾递归。编译器只是注意到最后一个操作是递归的。就是这样。

为什么这个貌似过多的关键字存在?我错过了什么吗?纯粹是为了方便编译器,而不是为了方便用户吗?

4 个答案:

答案 0 :(得分:11)

关键字告诉编译器该函数的实现必须是尾部递归的,并且如果该函数实际上不是尾部递归的,则使编译器报告错误。当功能实现的更改导致它不再是尾部递归的,并导致性能意外下降(或由于堆栈溢出错误导致生产完全失败)时,它可以保护用户免受伤害。 >

答案 1 :(得分:2)

我将继续猜测这是为了能够更加有意地编写尾递归函数。通过显式地要求关键字,您将知道编译器优化肯定会发生(您不会猜测编译器是否成功优化了函数,或者在运行时是否会出现堆栈溢出),加上代码将不会如果您违反了用tailrec编写的函数的尾部递归规则,则甚至可以进行编译,如文档所述:

  

要有资格使用tailrec修饰符,函数必须将其本身称为执行的最后一个操作。

答案 2 :(得分:0)

回想一下Kotlin的官方文档,它只是说:

  

当一个函数用tailrec修饰符标记并符合所需的形式时,编译器会优化递归,而留下一个快速,高效的基于循环的版本

强烈建议,如果不存在tailrec关键字,则不保证会转换为循环。

答案 3 :(得分:0)

基于@ szmb13 @yole答案的代码示例

尝试使用 n = 10000 运行此代码,如果遇到错误,请尝试添加 tailrec 关键字并再次运行

fun fibonacci(n: Int, a: BigInteger, b: BigInteger): BigInteger {
    return if (n == 0) b
    else fibonacci(n - 1, a + b, a)
}

您可以看到不同的