Swift 合并条件 FlatMap 结果

Swift Combine Conditional FlatMap Results

在使用 Swift Combine 时,如何为 flatMap 设置不同的 return 类型?我有我的第一个发布者,它发出一个值,然后我 flatMap 将其转换为一个新的发布者。但是,根据原始值,我可能需要 return 不同类型的不同发布者。

我在下面添加了一个基本示例。

import Combine


class Testing{
    var subscriptions = Set<AnyCancellable>()
    
    
    func getTestScore()->AnyPublisher<Int, Never>{
        return Just(80).eraseToAnyPublisher()
    }
    
    func congratulate()->AnyPublisher<String, Never>{
        return Just("Good Job!").eraseToAnyPublisher()
    }
    
    func getGPA()->AnyPublisher<Double, Never>{
        return Just(2.2).eraseToAnyPublisher()
    }
    
    init() {
        getTestScore()
            .flatMap{ score in
                if score < 70{
                    return self.getGPA()
                } else{
                    return self.congratulate()
                }
            }
            .sink { _ in } receiveValue: { value in
                print(value)
            }.store(in: &subscriptions)
    }
}

let testing = Testing()

正如 New Dev 所说,返回条件数据类型是不可能的——除非你不想将类型擦除为 Any

我的建议是创建一个专门的发布者,它会在分数超过(或低于)某个限制时发布。现在使用您的新发布者创建两个独立的、类型安全的管道。我知道您要求只使用一个管道。但是,我认为这种做法会给你带来更多的好处。

请在下面找到我的工作示例:

import Combine

class Testing{
    var subscriptions = Set<AnyCancellable>()
    
    func getTestScore()->AnyPublisher<Int, Never> {
        return Just(80).eraseToAnyPublisher()
    }
    
    func congratulate()->AnyPublisher<String, Never> {
        return Just("Good Job!").eraseToAnyPublisher()
    }
    
    func getGPA()->AnyPublisher<Double, Never> {
        return Just(2.2).eraseToAnyPublisher()
    }
    
    init() {
        let scoreExceedsLimit: AnyPublisher<Bool, Never> = getTestScore()
            .map { [=10=] >= 70 }
            .eraseToAnyPublisher()
        
        scoreExceedsLimit
            .filter { [=10=] == true }
            .flatMap { _ in self.congratulate() }
            .sink(receiveValue: { value in
                print("first pipeline: \(value)")
            })
            .store(in: &subscriptions)
        
        scoreExceedsLimit
            .filter { [=10=] == false }
            .flatMap { _ in self.getGPA() }
            .sink(receiveValue: { value in
                print("second pipeline: \(value)")
            })
            .store(in: &subscriptions)
    }
}

let testing = Testing()