泛型类的 Swift 扩展类型约束,其中泛型类型是另一种泛型类型

Mar*_*ark 6 generics type-constraints swift swift-extensions

我正在尝试了解 Swift 中的泛型类型约束。这是我的出发点:

\n\n
class Promise<T> {\n    func resolve(_ block:@escaping (T) ->Void) {}\n    func fulfill(_ result:T) {}\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

Promise 就是将来可以实现的事情。当它与 Swift 类型一起使用时,Result将结果从后台队列返回到主队列时,这会变得非常有用:

\n\n
let promise = Promise<Result<String, Error>>()\npromise.fulfill(.success("Hello"))\npromise.fulfill(.failure(NSError()))\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在我想向所有用于Result添加这些辅助方法的 Promise 实例添加扩展:

\n\n
extension Promise where T == Result<X, Error> {\n                                    \xe2\xac\x86\xef\xb8\x8e Here\'s the problem \xe2\x9a\xa1\xef\xb8\x8f\n    func failure(_ error:Error) {\n        fulfill(.failure(error))\n    }\n\n    func success(_ result:X) {\n        fulfill(.success(result))\n    }\n}\n\n// Shorter:\nlet promise = Promise<Result<String, Error>>()\npromise.success("Hello")\npromise.failure(NSError())\n
Run Code Online (Sandbox Code Playgroud)\n\n

唯一的问题是上面的代码无法编译,因为X没有定义。我想表达的是这样的:

\n\n

Promise当其泛型类型T为 where 类型Result<X,Z>X可以是任何内容且必须为\xe2\x86\x92Z类型时进行扩展。这可能吗?ErrorResult<*, Error>

\n

Rob*_*ier 7

你想要的都是可能的,只是语法有点冗长。您不能where对扩展施加限制。你必须把它放在每个方法上。

extension Promise {

    func failure<U>(_ error: Error) where T == Result<U, Error> {
        fulfill(.failure(error))
    }

    func success<U>(_ result: U) where T == Result<U, Error> {
        fulfill(.success(result))
    }
}
Run Code Online (Sandbox Code Playgroud)

您也可以使用协议来完成此操作,但对于枚举,我发现这非常笨拙,因为枚举案例不能被视为一致的方法。

protocol ResultType {
    associatedtype Success
    associatedtype Failure: Error
    static func makeFailure(_: Failure) -> Self
    static func makeSuccess(_: Success) -> Self
}

extension Result: ResultType {
    static func makeFailure(_ failure: Failure) -> Result<Success, Failure> { .failure(failure)  }
    static func makeSuccess(_ success: Success) -> Result<Success, Failure> { .success(success) }
}

extension Promise where T: ResultType {
    func failure(_ error: T.Failure) {
        fulfill(T.makeFailure(error))
    }

    func success(_ result: T.Success) {
        fulfill(T.makeSuccess(result))
    }
}
Run Code Online (Sandbox Code Playgroud)