在 Swift 5 的结果类型中指定自定义错误类型

ati*_*oSE 10 swift

我正在尝试Result使用 Foundation for Swift 5 中的内置 Result 类型创建一个具有自定义错误类型的变量,但我无法让类型系统理解我想要抛出的错误类型。

下面的代码不能编译。

import Foundation

enum CustomError: String, Error {
    case somethingBadHappened
}

struct Model {
    let value: Int
}

class Request {
    func execute(number: Int, completion: @escaping (Result<Model, CustomError>) -> Void) {
        let result = Result { () throws -> Model in
            if (number < 20) {
                throw CustomError.somethingBadHappened
            } else {
                return Model(value: number)
            }
        }
        // compiler complains here about: Cannot convert value of type 'Result<Model, Error>' to expected argument type 'Result<Model, CustomError>'
        completion(result)
    }
}

let request = Request()
request.execute(number: 19) { result in
    switch result {
    case .success(let value): print("Succeded with \(value)")
    case .failure(let error): print("Failed with \(error)")
    }

}
Run Code Online (Sandbox Code Playgroud)

将完成闭包的签名更改为completion: @escaping (Result<Model, Error>) -> Void有效,但随后我没有使用自定义错误类型。

如何让类型系统理解我想使用自定义错误类型?

mat*_*att 5

很抱歉给出第二个答案,但需要对 fphilipe 的答案进行纠正。

可以使用init(catching:)形成 Result 并将其作为Result<Model, CustomError>. 那mapError是为了什么!像这样:

enum CustomError: String, Error {
    case somethingBadHappened
}

struct Model {
    let value: Int
}

class Request {
    func execute(number: Int, completion: @escaping (Result<Model, CustomError>) -> Void) {
        let result = Result { () throws -> Model in
            if (number < 20) {
                throw NSError()
            } else {
                return Model(value: number)
            }
        }.mapError { err in
            return CustomError.somethingBadHappened
        }
        completion(result)
    }
}
Run Code Online (Sandbox Code Playgroud)

我必须抛出一些东西才能形成初始Result<Model, Error>,所以我只是抛出一个 NSError 作为一种占位符。但随后mapError出现并将其转换为Result<Model, CustomError>. 的力量mapError在于它只改变发生故障时发生的事情。

因此我们能够保持代码的原始形式。


fph*_*ipe 2

只需手动创建Result

let result: Result<Model, CustomError>
if (number < 20) {
    result = .failure(.somethingBadHappened)
} else {
    result = .success(Model(value: number))
}
completion(result)
Run Code Online (Sandbox Code Playgroud)