【问题标题】:Kotlin recursion stack overflowKotlin 递归堆栈溢出
【发布时间】:2018-12-02 22:21:21
【问题描述】:

我在 Kotlin 中编写了这个递归函数:

fun recursive(target: String, population: Population, debugFun: (String) -> Unit) : Population {
    if (population.solution(target).toString() == target) {
        return population
    }
    debugFun.invoke(population.solution(target).toString())
    return recursive(target, population.evolve(target), debugFun)
}

它将运行不确定的次数(因为我使用随机性来收敛进化算法中的解决方案)。我经常遇到堆栈溢出。 Kotlin/JVM 语言的最大堆栈深度是多少?我应该只以非递归方式编写函数吗?

【问题讨论】:

  • 或者我应该以这样一种方式编写它,即在函数的尾行进行递归调用以允许编译器使用尾递归进行优化?我不完全理解编译器如何优化尾递归。
  • 我已经编辑了问题以使用尾递归,因为同样的问题仍然存在!
  • Koltin 编译器尚未针对尾递归进行优化。您可以在集合上使用扩展函数而不是递归。

标签: recursion kotlin stack-overflow tail-recursion


【解决方案1】:

tailrec 关键字告诉 Kotlin 编译器使用尾递归。因此,它将递归展开为一个循环,这样您就可以摆脱 StackOverflowError。

tailrec fun recursive(target: String, population: Population, debugFun: (String) -> Unit) : Population {
    if (population.solution(target).toString() == target) {
        return population
    }
    debugFun.invoke(population.solution(target).toString())
    return recursive(target, population.evolve(target), debugFun)
}

因此,当使用 tailrec 时,编译器会创建与以下函数匹配的内容:

fun recursive(target: String, population: Population, debugFun: (String) -> Unit) : Population{
    var tmp = population

    while (true) {
        if (tmp.solution(target).toString() == target) {
            return tmp
        }
        debugFun.invoke(population.solution(target).toString())
        tmp = tmp.evolve(target)
    }
}

在这个函数中,不再进行任何方法调用,因此没有任何东西被推入堆栈,我们从 StackOverflowError 中保存。

请注意,我们仍然会陷入无限循环!

【讨论】:

猜你喜欢
  • 2020-03-06
  • 2015-04-04
  • 2017-01-20
  • 2017-09-06
  • 2019-07-08
  • 2015-08-05
  • 2017-09-29
  • 1970-01-01
  • 2018-03-10
相关资源
最近更新 更多