You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Combine的last(where:)操作符如何获取发射值?如何获取值4?

Combine中last(where:)无法获取值的问题及解决方案

问题代码

enum MyError: Error {
  case test
}
let subject = PassthroughSubject<Int, MyError>()
var subscriptions = Set<AnyCancellable>()

subject
  .eraseToAnyPublisher()
  .last(where: { $0 % 2 == 0 })
  .sink(receiveCompletion: { print("Completed with: ", $0) },
        receiveValue: { print($0) })
  .store(in: &subscriptions)

subject.send(1)
subject.send(2)
subject.send(4)
subject.send(completion: .failure(MyError.test))

当前输出

Completed with:  failure(__lldb_expr_1.MyError.test)

问题原因

last(where:)操作符的核心行为是:仅当上游Publisher正常完成(发送.finished事件)时,才会发射符合条件的最后一个值。如果上游以失败终止(发送.failure事件),该操作符会直接传递失败事件,不会触发receiveValue回调,自然无法输出你期望的4。

解决方案

方案1:捕获错误,让Publisher正常完成

通过catch操作符捕获上游错误,转换为正常完成的Publisher,这样last(where:)就能正常发射符合条件的最后值:

enum MyError: Error {
  case test
}
let subject = PassthroughSubject<Int, MyError>()
var subscriptions = Set<AnyCancellable>()

subject
  .eraseToAnyPublisher()
  .catch { _ in Empty<Int, Never>() } // 捕获错误后发送空的正常完成事件
  .last(where: { $0 % 2 == 0 })
  .sink(receiveCompletion: { print("Completed with: ", $0) },
        receiveValue: { print($0) }) // 会输出4
  .store(in: &subscriptions)

subject.send(1)
subject.send(2)
subject.send(4)
subject.send(completion: .failure(MyError.test))

输出结果:

4
Completed with:  finished

方案2:手动跟踪最后符合条件的值(保留错误信息)

如果需要保留上游的错误信息,同时获取最后符合条件的值,可以用scan操作符跟踪过程中的有效值:

enum MyError: Error {
  case test
}
let subject = PassthroughSubject<Int, MyError>()
var subscriptions = Set<AnyCancellable>()
var lastValidValue: Int?

subject
  .eraseToAnyPublisher()
  .scan(nil as Int?) { lastValid, current in
    current % 2 == 0 ? current : lastValid
  }
  .sink(receiveCompletion: { completion in
    print("Completed with: ", completion)
    if let value = lastValidValue {
      print(value) // 输出4
    }
  }, receiveValue: { value in
    lastValidValue = value
  })
  .store(in: &subscriptions)

subject.send(1)
subject.send(2)
subject.send(4)
subject.send(completion: .failure(MyError.test))

输出结果:

Completed with:  failure(__lldb_expr_1.MyError.test)
4

总结

要通过last(where:)获取值,必须保证上游Publisher最终是正常完成状态;如果需要保留错误事件,就得手动跟踪符合条件的最后值,再在完成回调中处理。

内容的提问来源于stack exchange,提问作者chlkdst

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 19:32:20