将接受转义闭包的闭包传递给接受该类型闭包的函数



在旧的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'通知的观察者收到他的响应时,他会向类发送一个包含y组合子和重复闭包的通知。一旦'sendData'通知的所有观察者实例都收到了它们的数据,

self.responses_received == responses_expected

为真,则不再调用f()。

现在,我的问题是,转换到Swift 3.0迫使我显式地声明'f'的类型为@escaping,在Y的定义上,像这样:

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标记。这可以编译,但感觉不对,我还没有测试过该转换是否在运行时实际工作。

我在这里错过了什么?

您的Y函数应该具有以下签名:

func Y<T, R>(_ f: @escaping (@escaping (T) -> R) -> ((T) -> R)) -> ((T) -> R)

因为它接受一个转义函数,而这个转义函数本身又需要一个转义函数。

当你调用Y时,闭包应该以:

开头
self.Y { (f: @escaping () -> ()) -> (() -> ()) in

注意,这个@escaping对应于Y签名中的第二个转义。是@escaping上的不匹配导致了编译器错误。

其余的大部分应该自行排序(一旦你更新dispatcher和NSNotificationCenter调用Swift 3)。

我在操场上有这段代码,它的构建没有任何问题:

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"

你可能想要清理你的构建和重新尝试构建,因为我没有得到修复建议在我的操场

最新更新