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.TryMapFailure 类型为 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.

中抛出任何其他类型的错误