为什么我不能在 Swift Combine 中的 .tryMap() 之后使用 .flatMap()?

Why can't I use .flatMap() after .tryMap() in Swift Combine?

我正在研究并尝试使用 Combine 来自己应用一些东西,并通过这个人为的示例遇到了以下情况..

let sequencePublisher = [70, 5, 17].publisher
var cancellables = [AnyCancellable]()

sequencePublisher
//    .spellOut()
    .flatMap { query -> URLSession.DataTaskPublisher in
        return URLSession.shared.dataTaskPublisher(for: URL(string: "http://localhost:3000?q=\(query)")!)
    }
    .compactMap { String(data: [=11=].data, encoding: .utf8) }
    .sink(receiveCompletion: { completion in
        switch completion {
        case .failure(let error):
            print(error.localizedDescription)
        default: print("finish")
        }
    }) { value in
        print(value)
    }
    .store(in: &cancellables)

我有一个发出 3 个整数的序列发布器,我通过 flatMap 传递它并向我的本地 API 发送一个 Get 请求请求,它只是 returns 返回相同的值嵌入字符串中。

一切正常,我在接收器中得到了所有 3 个 API 响应,只要我不取消注释 spellOut() 自定义运算符,如果数字是,该运算符应该会失败小于 6,这是它的作用:

enum ConversionError: LocalizedError {
    case lessThanSix(Int)
    var errorDescription: String? {
        switch self {
        case .lessThanSix(let n):
            return "could not convert number -> \(n)"
        }
    }
}

extension Publisher where Output == Int {
    func spellOut() -> Publishers.TryMap<Self, String> {
        tryMap { n -> String in
            let formatter = NumberFormatter()
            formatter.numberStyle = .spellOut
            guard n > 6, let spelledOut = formatter.string(from: n as NSNumber) else { throw ConversionError.lessThanSix(n) }
            return spelledOut
        }
    }
}

如果我在 flatMap 工作之前添加另一个 map 运算符,代码甚至不会编译,但是对于 tryMap 它只是说

No exact matches in call to instance method 'flatMap'

是否有任何方法可以实现此目的或为什么不允许这样做?

提前感谢您的回答

这里的问题是 FlatMap 要求在其闭包中创建的返回发布者与其上游具有相同的 Failure 类型(除非上游发生 Never 故障)。

因此,Sequence 发布商,例如:

let sequencePublisher = [70, 5, 17].publisher

故障类型为 Never,并且一切正常。

但是 TryMap,也就是 .spellOut 运算符 returns,有一个失败类型 Error,所以它失败了,因为 DataTaskPublisherURLError 故障类型。


一种修复方法是匹配 flatMap:

中的错误类型
sequencePublisher
    .spellOut()
    .flatMap { query in
        URLSession.shared.dataTaskPublisher(for: URL(...))
           .mapError { [=11=] as Error }
    }
    // etc...