首页 > 解决方案 > 为什么递归 swift 函数定义不会对其初始“值”产生问题?

问题描述

这里有很多关于尝试在 Swift 中定义递归闭包的有趣问题。我认为答案最清晰的是这篇文章,询问为什么不能在 Swift 的同一行中声明和定义递归闭包。但是,他们不会问相反的问题。也就是说,如果我不能创建这样的代码:

var countdown = { i in
    print(i)
    if i > 1 {
        countdown(i - 1)
    }
}
// error: Variable used within its own initial value

那为什么我可以写这样的代码:

func countdown(_ i: Int) {
    print(i)
    if i > 1 {
        countdown(i - 1)
    }
}

函数有什么特别之处,使它们在尝试在自己的声明中调用自己时没有任何问题?我理解闭包背后的问题:它试图捕获一个尚不存在的值(闭包本身)。但是,我不明白为什么该功能没有同样的问题。查看Swift Book,我们看到:

全局函数是具有名称且不捕获任何值的闭包。

这是一个半答案:上面的函数不会引起问题,因为函数不会捕获值。但是,如果函数不捕获值(尤其是递归值),它们如何工作?

标签: swiftfunctionrecursionclosures

解决方案


不太确定你在寻找什么答案。我的意思是,一个简单的答案是 Swift 编译器就是这样工作的。

一个原因可能是使用func表达式,例如func countdown(...) {},编译器可以安全地假设该函数将在它调用自身时定义。

而对于变量定义(即变量获取其值的表达式),它通常不会做出这样的假设,因为类似

var c = c + 1

由于相同的“在其自己的初始值中使用的变量”错误,显然无法正常工作。

话虽如此,编译器可能已经对闭包类型变量的定义进行了特殊定义,因为与非闭包变量不同,在定义它们时不需要它们的实际值。

这就是为什么一个解决方案是定义变量(或者至少重新向编译器保证它会被定义!),所以编译器不会抱怨:

var countdown: ((Int) -> Void)!
countdown = { i in
    print(i)
    if i > 1 {
        countdown(i - 1)
    }
}

推荐阅读