Swift Combine框架setFailureType错误操作符



出于科学原因,我创建了一个Publisher订户这样我就可以进入Combine了

已经转换从一个从不失败失败一。

enum IntegerError: String, Error {
case miltupleOf2 = "We are sorry but the number is a multiple of 2, therefore cannot be used in the process"
}
let integerPublisher = [1,3,3,3,3,3,5,6,7,7].publisher
.setFailureType(to: IntegerError.self)
let subscribtion = integerPublisher
.tryMap { intValue in
if intValue.isMultiple(of: 2) {
throw IntegerError.miltupleOf2
} else {
return intValue
}
}
.sink { completion in
switch completion {
case .finished:
print("success")
case .failure(let error):
if let error = error as? IntegerError {
print(error.rawValue)
} else {
print(error)
}
}
} receiveValue: { value in
print(value)
}

我的问题是:当使用sink时,错误类型为error. 为什么不自定义IntegerError.setFailureType修饰符?

将错误类型强制转换为前面指定的类型似乎有点多余。

谢谢。

原因很简单。tryMap返回一个Publishers.TryMap<Upstream, Output>,这是一个特定类型的发布者,Failure == Error:

typealias Failure = Error

所以只要你使用tryMap,setFailureType所做的就会撤销。

Publishers.TryMapError作为其Failure类型的原因是因为在Swift中,你不能指定闭包可以抛出的特定类型的错误(不像Java)。一旦将闭包标记为throws,就像tryMap对其transform参数所做的那样:

func tryMap<T>(_ transform: @escaping (Self.Output) throws -> T) -> Publishers.TryMap<Self, T>

任何Error都可以在transform闭包中抛出。您可以尝试更改throw IntegerError.miltupleOf2以抛出另一种类型的错误。你的代码仍然可以编译。


假设,如果Swift允许你指定在闭包中允许抛出的错误类型,那么tryMap可以被声明为(假语法):

func tryMap<T, E: Error>(_ transform: @escaping (Self.Output) throws E -> T) -> Publishers.TryMap<Self, T, E>

,你甚至不需要setFailureType


作为一种解决方法,您可以使用mapError将错误转换为所需的类型:

let subscribtion = integerPublisher
.tryMap { intValue -> Int in
if intValue.isMultiple(of: 2) {
throw IntegerError.miltupleOf2
} else {
return intValue
}
}.mapError { $0 as! IntegerError }
.sink { completion in
switch completion {
case .finished:
print("success")
case .failure(let error):
print(error.rawValue)
}
} receiveValue: { value in
print(value)
}

您需要向编译器保证您没有在tryMap中抛出任何其他类型的错误。

最新更新