如何在 Swift 中创建 _inline_ 递归闭包?
How do I create an _inline_ recursive closure in Swift?
Swift 中的全局函数递归很简单。例如:
func f()
{
f()
}
但是,闭包不能引用自身。例如:
var f: (Void -> Void) =
{
f()
}
产生以下错误:
Variable used within its own initial value
有解决办法吗?如何创建递归闭包 inline?
有一个解决方法:
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, [=10=]) }
return g
}
recursive
是一个接受闭包 (((T) -> U), T) -> U
的函数,其中 ((T) -> U)
是对闭包的剥离版本的引用,而 return 是一个可用函数, g
.
g
最初被分配了一个假函数(调用时崩溃)。这样做是为了启用新值 g
的递归,其中 g
与输入值 T
一起传递给 f
。重要的是要注意 g = { f(g, [=24=]) }
中的 g
指的是它自己,而不是之前分配给它的假函数。因此,每当在 f
中引用 ((T) -> U)
参数时,它就是对 g
的引用,后者又引用了自身。
此函数允许内联递归,如下所示:
recursive { f, x in x != 10 ? f(x + 1) : "success" }(0)
该函数共循环11次,无需声明单个变量。
更新: 这现在适用于 Swift 3 预览 6!
就我个人而言,我发现这是一个相当优雅的解决方案,因为我觉得它可以将我的代码简化到最低限度。 Y 组合器方法,例如下面的方法
func recursive<T, U>(_ f: (@escaping (@escaping (T) -> U) -> ((T) -> U))) -> ((T) -> U)
{
return { x in return f(recursive(f))(x) }
}
会让我 return 一个函数,一个在转义闭包中的转义闭包!
recursive { f in { x in x != 10 ? f(x + 1) : "success" } }(0)
如果没有内部 @escaping
属性,上面的代码将无效。它还需要另一组大括号,这使得它看起来比我在编写内联代码时习惯的更冗长。
限制是两个对象不能同时实例化,不能互相引用。必须先创建一个。您可以将函数标记为隐式解包可选。这样你用 nil
初始化函数,但是 "promise" 它稍后会有一个值。
var f: (Void -> Void)!
f = {
f()
}
更新:
另一种没有隐式解包选项的方法:
var f: (Void -> Void)
var placeholder: (Void -> Void) = {
f()
}
f = placeholder
Swift 中的全局函数递归很简单。例如:
func f()
{
f()
}
但是,闭包不能引用自身。例如:
var f: (Void -> Void) =
{
f()
}
产生以下错误:
Variable used within its own initial value
有解决办法吗?如何创建递归闭包 inline?
有一个解决方法:
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, [=10=]) }
return g
}
recursive
是一个接受闭包 (((T) -> U), T) -> U
的函数,其中 ((T) -> U)
是对闭包的剥离版本的引用,而 return 是一个可用函数, g
.
g
最初被分配了一个假函数(调用时崩溃)。这样做是为了启用新值 g
的递归,其中 g
与输入值 T
一起传递给 f
。重要的是要注意 g = { f(g, [=24=]) }
中的 g
指的是它自己,而不是之前分配给它的假函数。因此,每当在 f
中引用 ((T) -> U)
参数时,它就是对 g
的引用,后者又引用了自身。
此函数允许内联递归,如下所示:
recursive { f, x in x != 10 ? f(x + 1) : "success" }(0)
该函数共循环11次,无需声明单个变量。
更新: 这现在适用于 Swift 3 预览 6!
就我个人而言,我发现这是一个相当优雅的解决方案,因为我觉得它可以将我的代码简化到最低限度。 Y 组合器方法,例如下面的方法
func recursive<T, U>(_ f: (@escaping (@escaping (T) -> U) -> ((T) -> U))) -> ((T) -> U)
{
return { x in return f(recursive(f))(x) }
}
会让我 return 一个函数,一个在转义闭包中的转义闭包!
recursive { f in { x in x != 10 ? f(x + 1) : "success" } }(0)
如果没有内部 @escaping
属性,上面的代码将无效。它还需要另一组大括号,这使得它看起来比我在编写内联代码时习惯的更冗长。
限制是两个对象不能同时实例化,不能互相引用。必须先创建一个。您可以将函数标记为隐式解包可选。这样你用 nil
初始化函数,但是 "promise" 它稍后会有一个值。
var f: (Void -> Void)!
f = {
f()
}
更新: 另一种没有隐式解包选项的方法:
var f: (Void -> Void)
var placeholder: (Void -> Void) = {
f()
}
f = placeholder