递归对于Swift中的全局函数来说是微不足道的。例如:
func f()
{
f()
}
然而,封闭不能指自己。例如:
var f: (Void -> Void) =
{
f()
}
产生以下错误:
Variable used within its own initial value
这有解决方法吗?如何创建递归闭包内嵌?
答案 0 :(得分:15)
限制是两个对象无法同时实例化并相互引用。必须在另一个之前创建一个。您可以将函数标记为隐式解包可选。这样您可以使用nil
初始化函数,但“保证”它稍后会有一个值。
var f: (Void -> Void)!
f = {
f()
}
<强>更新强> 另一种没有隐式解包的选项的方法:
var f: (Void -> Void)
var placeholder: (Void -> Void) = {
f()
}
f = placeholder
答案 1 :(得分:4)
有一种解决方法:
func unimplemented<T>() -> T
{
fatalError()
}
func recursive<T, U>(f: (@escaping (((T) -> U), T) -> U)) -> ((T) -> U)
{
var g: ((T) -> U) = { _ in unimplemented() }
g = { f(g, $0) }
return g
}
recursive
是一个带有闭包(((T) -> U), T) -> U
的函数,其中((T) -> U)
是对闭包的剥离版本的引用,并返回一个可用的函数g
。
g
最初被分配了一个假功能(在通话时崩溃)。这样做是为了启用新值g
的递归,其中g
传递给f
以及输入值T
。重要的是要注意g
中的g = { f(g, $0) }
是指自身,而不是之前分配给它的假函数。因此,只要在((T) -> U)
中引用了f
参数,它就会引用g
,而recursive { f, x in x != 10 ? f(x + 1) : "success" }(0)
则会引用自身。
此函数允许内联递归,如下所示:
func recursive<T, U>(_ f: (@escaping (@escaping (T) -> U) -> ((T) -> U))) -> ((T) -> U)
{
return { x in return f(recursive(f))(x) }
}
此函数总共重复11次,无需声明单个变量。
更新:现在可以使用Swift 3预览6了!
就个人而言,我发现这是一个相当优雅的解决方案,因为我觉得它将我的代码简化到最低限度。 Y组合方法,如下面的
recursive { f in { x in x != 10 ? f(x + 1) : "success" } }(0)
会让我返回一个函数,一个逃逸的闭包在一个逃逸的闭包中!
@escaping
如果不是内部EXISTS
属性,则上述代码无效。它还需要另一组括号,这使得它看起来比我在编写内联代码时所熟悉的更加冗长。