【发布时间】:2020-11-10 10:39:21
【问题描述】:
我在函数完成块中使用了 swift Result<> 泛型,但将其传递给具有协议类型的另一个完成块无法按预期工作。
public protocol Journey { }
class CommsJourney: Journey { }
typealias Completion = (Result<[Journey]?, Error>) -> Void
typealias CommsCompletion = (Result<[CommsJourney]?, Error>) -> Void
class Comms {
func refreshTimes(completion: @escaping CommsCompletion) {
let array = [CommsJourney()]
completion(.success(array))
}
}
/**
Completion block returns `Journey` protocol if successful
*/
func refreshTimes(completion: @escaping Completion) {
// Passing the previous completion block fails to compile as signatures are different
// Comms().refreshTimes(completion: completion)
Comms().refreshTimes { (result) in
switch result {
case .success(let results):
// result is `CommsCompletion` yet returns perfectly fine
completion(.success(results))
case .failure(let error):
completion(.failure(error))
}
}
}
无法转换“完成”类型的值(又名 '(Result
, Error>) -> ()') 达到预期 参数类型“CommsCompletion”(又名 '(Result , Error>) -> ()')
我想了解为什么传递完成不起作用,但发送结果却可以。还有什么是纠正这个问题的最佳方法?我的switch 示例是最简单/最好的解决方案吗?
编辑----
有人向我指出这个 q/a Swift generic coercion misunderstanding 要么完全超出我的想象,要么不是针对我的情况。因为我可以通过简单地提取result 然后转发它来解决这个问题,创建一个中间Any... 对象似乎有点过分。
编辑 ----- 游乐场要点在这里https://gist.github.com/ddaddy/d58b648dbe82a1c63fe23541cc1aad40
【问题讨论】:
-
我不明白你怎么会感到困惑。 :) 完成不是 CommsCompletion。因此,当它需要 CommsCompletion 时,您不能使用 Completion 调用
refreshTimes。困难的部分是什么?我要香蕉,你给我大象;那不编译。完毕。 (在起作用的那个中,它与开关无关。您可以删除整个主体,它仍然可以编译。只是您更改了签名,以便refreshTimes期望完成。我要一头大象,而您给我一头大象。) -
好的,我明白了,虽然它们是同一个协议,但它们是不同的完成类型签名。我没有清楚地写我的(有效的),所以我编辑了它。我可以成功地将完成结果从一种完成块类型传递给另一种。
-
所以 Journey 是一个协议? — 您能否使用实际代码进行编辑,而不仅仅是使用我们必须自己猜测和填写的名称的摘录?如果您需要实际帮助,请提供minimal reproducible example。
-
是的。我很抱歉我错过了。实际的代码是一个非常大的代码库的一部分,所以我不得不把它去掉。我通常很擅长我的详细信息,但肯定是度过了一个愉快的早晨。
-
好吧,我不会改变我所说的任何内容。您是说,在
class Comms中,您声明了func refreshTimes(completion: @escaping CommsCompletion) { },但它无法编译。如果您将 CommsCompletion 更改为 Completion,则可以。函数调用中的类型和该函数声明中的类型必须匹配。函数的内容与故事无关。
标签: swift generics swift-protocols