Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin的tailrec有什么意义?_Kotlin - Fatal编程技术网

Kotlin的tailrec有什么意义?

Kotlin的tailrec有什么意义?,kotlin,Kotlin,tailrec优化存在尾部递归的函数。为什么编译器不直接优化它呢 C编译器优化尾部递归。您不必将该方法标记为具有尾部递归。编译器只是注意到最后一个操作是递归的。就这样 为什么这个看似过多的关键字会存在?我错过什么了吗?这纯粹是为了方便编译器,而不是为了方便用户吗?关键字告诉编译器函数的实现必须是尾部递归的,如果函数实际上不是尾部递归的,则会导致编译器报告错误。当对函数实现的更改导致函数不再是尾部递归,并导致性能意外下降(或由于堆栈溢出错误导致生产完全失败)时,它可以保护用户.我将继续并猜测这是为

tailrec
优化存在尾部递归的函数。为什么编译器不直接优化它呢

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


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

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

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

要符合tailrec修饰符的条件,函数必须在执行最后一个操作时调用自身


回想一下Kotlin的官方文件只是说:

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


这强烈表明,如果tailrec关键字不存在,则不保证进行循环转换。

基于@szmb13@yole answers的代码示例

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

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

您可以看到不同的

,那么这是否意味着即使符合条件,也不会针对尾部递归优化未标记tailrec的函数?这确实给人留下了这样的印象(至少对我是这样)。这让我想知道它是否真的只是给出编译器提示。这部分是b/c,JVM本身目前无法针对尾部递归进行优化(请参阅)。JVM上的许多语言,例如Clojure和Kotlin,都公开了一个表单(在Clojure中重复出现)或一个关键字(在Kotlin中tailrec),以便在语言级别上捕捉到这一点。@HelloWorld,我知道Clojure是这样,Kotlin也是这样。根据文档,Kotlin编译器需要关键字
tailrec
来进行优化。编译器不需要提示来检测尾部递归函数;这是一张相当微不足道的支票。我已经解释了这个关键字存在的原因。如果你不相信你给出的答案,问问题有什么意义?@yole-Yours和zsmb13似乎相当,他只比我快了一盎司,所以我把他的答案标记为正确。然而,阅读tankthinks reply让我重新思考。如果这是真的,为什么你不能有一个既能
打开
又能
tailrec
的方法呢?我也对这个限制很好奇,并了解到它最初是受支持的,但后来由于编译问题被阻止:@yole似乎应该有比禁用
open
成员上的
tailrec
修饰符更好的解决方案。如果最终能够取消这一限制,那将是一件好事。