Swift Result<> 无法转换为 downcast 结果
Swift Result<> cannot convert to downcast result
我在函数完成块中使用 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))
}
}
}
Cannot convert value of type 'Completion' (aka
'(Result<Optional<Array>, Error>) -> ()') to expected
argument type 'CommsCompletion' (aka
'(Result<Optional<Array>, Error>) -> ()')
我想了解为什么通过完成不起作用,但发送结果却起作用。还有什么是纠正这个问题的最佳方法?我的 switch
示例是 easiest/best 解决方案吗?
编辑----
有人向我指出了这个 q/a ,它要么完全超出了我的理解范围,要么不是针对我的情况。因为我可以通过简单地提取 result
然后转发它来解决这个问题,所以创建一个中间 Any...
对象似乎有点过分了。
编辑 -----
游乐场要点在这里 https://gist.github.com/ddaddy/d58b648dbe82a1c63fe23541cc1aad40
好的,所以这不会编译:
public protocol Journey { }
class CommsJourney: Journey { }
typealias CommsCompletion = (Result<[CommsJourney]?, Error>) -> Void
class Comms {
func refreshTimes(completion: @escaping CommsCompletion) { }
}
typealias Completion = (Result<[Journey]?, Error>) -> Void
func callerOfRefreshTimes(completion: @escaping Completion) {
Comms().refreshTimes(completion: completion) // nope
}
那是因为您正试图在需要 CommCompletion 函数的地方传递 Completion 函数,并且它们是完全不同的函数类型,所以类型不匹配,编译器会报错。
要理解第二个示例为何有效,让我们对其进行简化。所以,这个编译很好:
public protocol Journey { }
class CommsJourney: Journey { }
typealias CommsCompletion = (Result<[CommsJourney]?, Error>) -> Void
class Comms {
func refreshTimes(completion: @escaping CommsCompletion) { }
}
typealias Completion = (Result<[Journey]?, Error>) -> Void
func callerOfRefreshTimes(completion: @escaping Completion) {
Comms().refreshTimes { _ in
let r : Result<[Journey]?, Error> = .success([CommsJourney]()) // <--
completion(r)
}
}
我们所做的只是创建一个正确类型 的结果 并将其传递给 completion
函数调用。的确,我们通过使用 CommsJourney 数组而不是结果类型所需的 Journey 数组形成 结果,但这是多态性在起作用:您可以提供一个期望超类型数组的子类型数组。
所以在第二个代码中,我们只对数组使用多态替换。但是我们不在其他地方使用任何多态替换。特别是,我们正在创建的结果的类型 完全 作为 completion
函数期望的参数类型。你在你的代码中做同样的事情,但是你是通过隐式类型来做的,所以它不是那么明显。
当然,在您的代码中,值 result
作为周围闭包的参数到达这一事实只是一个转移注意力的问题!您在代码中做的第一件事就是将 Result 分开并 extract 其中的数组。然后你扔掉原来的结果!
因此,您不要尝试传递错误的结果类型,也不要尝试强制转换结果;相反,您只需丢弃第一个结果并创建一个全新的结果(正确类型 ) 并传递它(这就是为什么我编写代码来演示这样做的原因)。
我在函数完成块中使用 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))
}
}
}
Cannot convert value of type 'Completion' (aka '(Result<Optional<Array>, Error>) -> ()') to expected argument type 'CommsCompletion' (aka '(Result<Optional<Array>, Error>) -> ()')
我想了解为什么通过完成不起作用,但发送结果却起作用。还有什么是纠正这个问题的最佳方法?我的 switch
示例是 easiest/best 解决方案吗?
编辑----
有人向我指出了这个 q/a result
然后转发它来解决这个问题,所以创建一个中间 Any...
对象似乎有点过分了。
编辑 ----- 游乐场要点在这里 https://gist.github.com/ddaddy/d58b648dbe82a1c63fe23541cc1aad40
好的,所以这不会编译:
public protocol Journey { }
class CommsJourney: Journey { }
typealias CommsCompletion = (Result<[CommsJourney]?, Error>) -> Void
class Comms {
func refreshTimes(completion: @escaping CommsCompletion) { }
}
typealias Completion = (Result<[Journey]?, Error>) -> Void
func callerOfRefreshTimes(completion: @escaping Completion) {
Comms().refreshTimes(completion: completion) // nope
}
那是因为您正试图在需要 CommCompletion 函数的地方传递 Completion 函数,并且它们是完全不同的函数类型,所以类型不匹配,编译器会报错。
要理解第二个示例为何有效,让我们对其进行简化。所以,这个编译很好:
public protocol Journey { }
class CommsJourney: Journey { }
typealias CommsCompletion = (Result<[CommsJourney]?, Error>) -> Void
class Comms {
func refreshTimes(completion: @escaping CommsCompletion) { }
}
typealias Completion = (Result<[Journey]?, Error>) -> Void
func callerOfRefreshTimes(completion: @escaping Completion) {
Comms().refreshTimes { _ in
let r : Result<[Journey]?, Error> = .success([CommsJourney]()) // <--
completion(r)
}
}
我们所做的只是创建一个正确类型 的结果 并将其传递给 completion
函数调用。的确,我们通过使用 CommsJourney 数组而不是结果类型所需的 Journey 数组形成 结果,但这是多态性在起作用:您可以提供一个期望超类型数组的子类型数组。
所以在第二个代码中,我们只对数组使用多态替换。但是我们不在其他地方使用任何多态替换。特别是,我们正在创建的结果的类型 完全 作为 completion
函数期望的参数类型。你在你的代码中做同样的事情,但是你是通过隐式类型来做的,所以它不是那么明显。
当然,在您的代码中,值 result
作为周围闭包的参数到达这一事实只是一个转移注意力的问题!您在代码中做的第一件事就是将 Result 分开并 extract 其中的数组。然后你扔掉原来的结果!
因此,您不要尝试传递错误的结果类型,也不要尝试强制转换结果;相反,您只需丢弃第一个结果并创建一个全新的结果(正确类型 ) 并传递它(这就是为什么我编写代码来演示这样做的原因)。