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 其中的数组。然后你扔掉原来的结果!

因此,您不要尝试传递错误的结果类型,也不要尝试强制转换结果;相反,您只需丢弃第一个结果并创建一个全新的结果正确类型 ) 并传递它(这就是为什么我编写代码来演示这样做的原因)。