Swift 4中的尾递归(尾调用优化)

6

我尝试在Swift中实现以下简单的函数:

 func sum (n: Int, currentSum: Int = 0) -> Int {
    return n == 0 ? currentSum :
                    sum(n: n-1,
                        currentSum: currentSum + n)
 }

我原本期望编译器会使用尾递归优化。但我遇到了(字面上的)栈溢出问题。

我需要设置什么标志(flag)来让编译器进行这种优化呢?是我的代码有误或是该编译器优化不可用吗?

谢谢!


3
你是否以发布模式编译(即启用了优化)? - Martin R
1
对于对编译器如何实现TCO感兴趣的读者,请参阅WWDC 2015视频深入剖析。尽管这是Objective-C,但基本概念是相同的。这是一个很好的视觉演示,展示了在进行此优化时堆栈中正在发生的事情。 - Rob
2个回答

6

正如马丁所指出的,除非你启用优化器(-O),否则无论如何都不会得到TCO。但即使在这种情况下,也没有办法保证你会得到TCO,因此你真的不能依赖它。Swift对递归算法并不特别友好。通常你会这样写:

func sum(n: Int) -> Int {
    return (1...n).reduce(0, +)    
}

或者保持相同的计算模式(即从n开始倒数到1):
func sum(n: Int) -> Int {
    return (1...n).reversed().reduce(0, +)
}

0
有没有什么标志需要设置来让编译器进行这样的优化,我在代码上犯了什么错误或者这个编译器优化不可用?
一般来说,由于选择了自动引用计数(ARC)进行内存管理,你不能依赖于Swift中的尾调用优化。
如果一个函数需要释放内存,那么编译器会插入代码在函数末尾执行释放操作。因此,防止尾调用位置的调用被编译为尾调用。

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