将采用转义闭包的闭包传递给接受该类型闭包的函数的问题
Issue passing a closure that takes an escaping closure to a function that accepts a closure of that type
在旧的 swift 世界中(我相信是 2.0)我有以下 Y 组合器实现
func Y<T, R>( f: (T -> R) -> (T -> R) ) -> (T -> R) {
return { (t: T) -> R in
return f(self.Y(f))(t)
}
}
我会在别处调用 Y 梳来创建递归闭包,如下所示:
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
let repeatClosure = self.Y {
(f: () -> () ) -> (() -> ()) in
return {
if self.responses_received != responses_expected {
dispatch_after(delayTime, dispatch_get_main_queue()) {
// Resend
NSNotificationCenter.defaultCenter().
postNotificationName(sendData,
object: nil, userInfo: dataToSend)
f()
}
} else {
print("Completed!")
self.responses_received = 0
}
}
}
repeatClosure()
想法是,当 'sendData' 通知的观察者收到他的回复时,他会向 class 发送一个通知,其中包含我的 Y 组合器和重复闭包。一旦 'sendData' 通知的所有观察者实例都收到了它们的数据,
self.responses_received == responses_expected
会是真的,我们不会再调用 f()。
现在,我的问题是向 Swift 3.0 的转换迫使我在 Y 的定义中明确声明 'f' 的类型为 @escaping,如下所示:
func Y<T, R>( _ f: @escaping ((T) -> R) -> ((T) -> R) ) -> ((T) -> R) {
return { (t: T) -> R in
return f(self.Y(f))(t)
}
}
随后将我的重复闭包转换为相同类型。很好,我理解@escaping 和@noescape 之间的区别以及为什么我的代码需要它。但是,在尝试构建时,我收到有关类型不匹配的编译错误:
Cannot convert value of type '(@escaping () -> ()) -> (() -> ())'
to expected argument type '(() -> ()) -> (() -> ())'
我创建了一个简单的示例闭包只是为了测试它给出了相同的错误:
let innerClosure = { (f: @escaping ()->()) -> (()->()) in
return {}
}
let repeatClosure = self.Y(innerClosure)
而以下没有问题:
let innerClosure = { (f: ()->()) -> (()->()) in
return {}
}
let repeatClosure = self.Y(innerClosure)
我从 fixit 那里得到了强制转换为类型的建议,没有 @escaping 标记。这可以编译,但感觉不对,而且我还没有实际测试过该转换是否会在 运行 时间真正起作用。
我在这里错过了什么?
我在操场上有这段代码,它可以毫无问题地构建:
class Foo {
func Y<T,R>(_ f: @escaping ((T) -> R) -> ((T) -> R) ) -> ((T) -> R) {
return { (t: T) -> R in
return f(self.Y(f))(t)
}
}
func test() {
let innerClosure = { (f: ()->()) -> (()->()) in
print("test")
return {}
}
let repeatClosure = self.Y(innerClosure)
repeatClosure()
}
}
Foo().test() // prints "test"
您可能想要清理您的构建并重新尝试构建,因为我在 playground 中没有得到修复建议。
您的 Y
函数应具有以下签名:
func Y<T, R>(_ f: @escaping (@escaping (T) -> R) -> ((T) -> R)) -> ((T) -> R)
因为它接受一个本身需要转义函数的转义函数。
当您调用 Y
时,闭包应该以:
开头
self.Y { (f: @escaping () -> ()) -> (() -> ()) in
注意这个@escaping
对应于Y
签名中转义的second。这是导致您的编译器错误的 @escaping
不匹配。
其余大部分应该自行解决(一旦您将 Dispatch 和 NSNotificationCenter 调用更新为 Swift 3)。
在旧的 swift 世界中(我相信是 2.0)我有以下 Y 组合器实现
func Y<T, R>( f: (T -> R) -> (T -> R) ) -> (T -> R) {
return { (t: T) -> R in
return f(self.Y(f))(t)
}
}
我会在别处调用 Y 梳来创建递归闭包,如下所示:
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
let repeatClosure = self.Y {
(f: () -> () ) -> (() -> ()) in
return {
if self.responses_received != responses_expected {
dispatch_after(delayTime, dispatch_get_main_queue()) {
// Resend
NSNotificationCenter.defaultCenter().
postNotificationName(sendData,
object: nil, userInfo: dataToSend)
f()
}
} else {
print("Completed!")
self.responses_received = 0
}
}
}
repeatClosure()
想法是,当 'sendData' 通知的观察者收到他的回复时,他会向 class 发送一个通知,其中包含我的 Y 组合器和重复闭包。一旦 'sendData' 通知的所有观察者实例都收到了它们的数据,
self.responses_received == responses_expected
会是真的,我们不会再调用 f()。
现在,我的问题是向 Swift 3.0 的转换迫使我在 Y 的定义中明确声明 'f' 的类型为 @escaping,如下所示:
func Y<T, R>( _ f: @escaping ((T) -> R) -> ((T) -> R) ) -> ((T) -> R) {
return { (t: T) -> R in
return f(self.Y(f))(t)
}
}
随后将我的重复闭包转换为相同类型。很好,我理解@escaping 和@noescape 之间的区别以及为什么我的代码需要它。但是,在尝试构建时,我收到有关类型不匹配的编译错误:
Cannot convert value of type '(@escaping () -> ()) -> (() -> ())'
to expected argument type '(() -> ()) -> (() -> ())'
我创建了一个简单的示例闭包只是为了测试它给出了相同的错误:
let innerClosure = { (f: @escaping ()->()) -> (()->()) in
return {}
}
let repeatClosure = self.Y(innerClosure)
而以下没有问题:
let innerClosure = { (f: ()->()) -> (()->()) in
return {}
}
let repeatClosure = self.Y(innerClosure)
我从 fixit 那里得到了强制转换为类型的建议,没有 @escaping 标记。这可以编译,但感觉不对,而且我还没有实际测试过该转换是否会在 运行 时间真正起作用。
我在这里错过了什么?
我在操场上有这段代码,它可以毫无问题地构建:
class Foo {
func Y<T,R>(_ f: @escaping ((T) -> R) -> ((T) -> R) ) -> ((T) -> R) {
return { (t: T) -> R in
return f(self.Y(f))(t)
}
}
func test() {
let innerClosure = { (f: ()->()) -> (()->()) in
print("test")
return {}
}
let repeatClosure = self.Y(innerClosure)
repeatClosure()
}
}
Foo().test() // prints "test"
您可能想要清理您的构建并重新尝试构建,因为我在 playground 中没有得到修复建议。
您的 Y
函数应具有以下签名:
func Y<T, R>(_ f: @escaping (@escaping (T) -> R) -> ((T) -> R)) -> ((T) -> R)
因为它接受一个本身需要转义函数的转义函数。
当您调用 Y
时,闭包应该以:
self.Y { (f: @escaping () -> ()) -> (() -> ()) in
注意这个@escaping
对应于Y
签名中转义的second。这是导致您的编译器错误的 @escaping
不匹配。
其余大部分应该自行解决(一旦您将 Dispatch 和 NSNotificationCenter 调用更新为 Swift 3)。