Go语言中的尾调用优化

53

截至目前,Go编程语言是否优化尾调用?如果没有,它是否至少优化函数对其本身的尾递归调用?


2
如果我遵循 https://groups.google.com/forum/?fromgroups=#!topic/golang-nuts/iveUW_2--cI,不是很确定。 - VonC
你可以通过编写一个尾递归函数,然后编写它的迭代等效函数并比较内存使用情况来进行测试。 - Snowball
3
"尾调用消除并不是真正的优化,因为关闭它会改变程序的可运行性。" - Jesse
不,他们不会这样做 https://github.com/golang/go/issues/22624 - Bhupesh Varshney
4个回答

20

有关“Go在某些情况下支持尾递归”的说法可以在邮件列表中找到:

在6g / 8g的某些情况下已经实现了,在gccgo中更为普遍。

我们目前没有计划更改语言以要求编译器在所有情况下实现尾调用优化。如果您必须使用尾调用,则可以使用循环或goto语句。

如果想了解这些情况,最好深入研究golang源代码,该代码是开放的。


3
您不能将所有的尾调用都替换为循环或goto语句。 - user1804599
1
@райтфолд:从技术上讲,你可以这样做,但如果你不得不重写代码使其成为一个函数,那将会变得非常丑陋。 - Matt
1
你可以始终使用跳板实现代码中的尾调用,但这需要进行全局重写,并以单子模式编写代码,而没有泛型会更加困难(尽管Go将在2022年获得它们)。 - saolof

5

我刚写了一个新的库来解决这个限制。多亏了 Go 1.18 新引入的泛型语言特性,现在我们可以实现类型安全的无栈互递归函数。

https://github.com/kandu/go_tailcall


2
当您引用自己的内容时,请务必阅读Stack Overflow的自我推广政策 - Jeremy Caney

4

扩展@Rostyslav出色的答案。如果你必须要有一个尾调用,在这个例子中是一个尾递归调用,你可以像这样做。

package main

import "fmt"

func tail(i int) {
    if i == 0 {
        return
    } else {
        fmt.Println(i)
        tail(i - 1) //tail recursive call
    }
}
func main() {
    tail(3) //3, 2, 1
}

3

这并不是事实。据邮件列表中核心开发团队表示,也没有任何计划。


1
这还是现状吗? - matanster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接