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

ct2axkht  于 2022-11-21  发布在  Swift
关注(0)|答案(2)|浏览(120)

我正在研究和尝试一些东西与合并应用对我自己和进入以下情况与这个人为的例子。

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: $0.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请求,该API只返回嵌入到字符串中的相同值。
一切正常,我在sink中得到了所有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,它只会说
对示例方法“flatMap”的调用中没有完全匹配项
有没有办法做到这一点,或者为什么不允许?
提前感谢您的回答

2izufjch

2izufjch1#

这里的问题是FlatMap要求在其闭包中创建的返回发布者具有与其上游相同的Failure类型(除非上游有Never故障)。
因此,一个Sequence发布者,例如:

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

故障类型为Never且全部正常。
但是.spellOut运算符返回的TryMap具有Error的故障类型,因此它失败,因为DataTaskPublisher具有URLError故障类型。
一种修复方法是匹配flatMap

sequencePublisher
    .spellOut()
    .flatMap { query in
        URLSession.shared.dataTaskPublisher(for: URL(...))
           .mapError { $0 as Error }
    }
    // etc...
vnjpjtjt

vnjpjtjt2#

您必须在tryMap之后Map错误。

publisher
        .tryMap({ id in
            if let id = id { return id } else { throw MyError.unknown("noId") }
        })
        .mapError { $0 as? MyError ?? MyError.unknown("noId") }
        .flatMap { id -> AnyPublisher<Model, MyError> in
            fetchDataUseCase.execute(id: id)
        }
        .eraseToAnyPublisher()

相关问题