Swift Combine framework setFailureType 错误运算符
Swift Combine framework setFailureType error operator
出于科学原因,我创建了一个 Publisher 和一个 Subscriber,这样我就可以深入了解 Combine。
Publisher 已从永不失败 转换为失败。
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。为什么不是我在 .setFailureType 修饰符中使用的自定义 IntegerError?
将我的错误转换为我之前指定的类型的需要似乎有点多余。
谢谢。
这样做的原因很简单。 tryMap
returns一个Publishers.TryMap<Upstream, Output>
, which is a specific kind of publisher with Failure == Error
:
typealias Failure = Error
因此,一旦您使用 tryMap
,就会撤消 setFailureType
所做的事情。
Publishers.TryMap
的 Failure
类型为 Error
的原因是因为在 Swift 中,您无法指定闭包可以抛出的特定类型的错误(例如,不同于 Java)。一旦你将一个闭包标记为 throws
,就像 tryMap
已经完成了它的 transform
参数:
func tryMap<T>(_ transform: @escaping (Self.Output) throws -> T) -> Publishers.TryMap<Self, T>
any 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 { [=13=] as! IntegerError }
.sink { completion in
switch completion {
case .finished:
print("success")
case .failure(let error):
print(error.rawValue)
}
} receiveValue: { value in
print(value)
}
您需要向编译器保证您没有在 tryMap
.
中抛出任何其他类型的错误
出于科学原因,我创建了一个 Publisher 和一个 Subscriber,这样我就可以深入了解 Combine。
Publisher 已从永不失败 转换为失败。
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。为什么不是我在 .setFailureType 修饰符中使用的自定义 IntegerError?
将我的错误转换为我之前指定的类型的需要似乎有点多余。
谢谢。
这样做的原因很简单。 tryMap
returns一个Publishers.TryMap<Upstream, Output>
, which is a specific kind of publisher with Failure == Error
:
typealias Failure = Error
因此,一旦您使用 tryMap
,就会撤消 setFailureType
所做的事情。
Publishers.TryMap
的 Failure
类型为 Error
的原因是因为在 Swift 中,您无法指定闭包可以抛出的特定类型的错误(例如,不同于 Java)。一旦你将一个闭包标记为 throws
,就像 tryMap
已经完成了它的 transform
参数:
func tryMap<T>(_ transform: @escaping (Self.Output) throws -> T) -> Publishers.TryMap<Self, T>
any 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 { [=13=] as! IntegerError }
.sink { completion in
switch completion {
case .finished:
print("success")
case .failure(let error):
print(error.rawValue)
}
} receiveValue: { value in
print(value)
}
您需要向编译器保证您没有在 tryMap
.