我正在尝试创建一个带有自定义错误类型的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)")
}
}
可以将完成闭包的签名更改为completion: @escaping (Result<Model, Error>) -> Void
,但是我没有使用自定义错误类型。
如何使类型系统理解我想使用自定义错误类型?
答案 0 :(得分:2)
为第二个答案道歉,但需要对fphilipe的答案进行纠正。
您可以使用init(catching:)
来形成结果,然后将其作为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)
}
}
我必须抛出 something 才能形成初始的Result<Model, Error>
,所以我只是抛出NSError作为一种占位符。但是随后出现mapError
并将其转换为Result<Model, CustomError>
。 mapError
的强大之处在于它仅更改发生故障时发生的情况。
因此我们能够保留代码的原始形式。
答案 1 :(得分:1)
将完成闭包的签名更改为
completion: @escaping (Result<Model, Error>) -> Void
可以,但是我没有使用自定义错误类型。
是的,你是!完全以这种方式更改签名,以便您进行编译,然后运行代码。当我们到达这一行时:
case .failure(let error): print("Failed with \(error)")
...我们打印"Failed with somethingBadHappened"
。证明您的CustomError.somethingBadHappened
实例通过得很好。
如果问题是您想显式地分离出CustomError,则在捕获时将其显式地分离出来:
case .failure(let error as CustomError): print(error)
default : fatalError("oops, got some other error")
或者,如果您想进一步了解和发现.somethingBadHappened
情况,请指定:
case .failure(CustomError.somethingBadHappened): print("Something bad happened")
default : fatalError("oops, got some other error")
这些示例是人为的,但是它们演示了它们打算演示的内容-CustomError实例正以完全完整性来实现。
答案 2 :(得分:0)
只需手动创建Result
:
let result: Result<Model, CustomError>
if (number < 20) {
result = .failure(.somethingBadHappened)
} else {
result = .success(Model(value: number))
}
completion(result)