如何将发送呼叫从一个 PassthroughSubject 转发到另一个(即 PassthroughSubject 链接)?

How to forward send calls from one PassthroughSubject to another (i.e. PassthroughSubject chaining)?

假设我有一个 API 用于 class,它使用 PassthroughSubject 接收其输入:

class Logger {
  let log: PassthroughSubject<String, Never>
}

通常我可以通过调用 logger.log.send("test").

发出一个值

现在说我想在这个通用记录器和我的代码之间拥有自己的记录器:

class MyLogger {
  let log: PassthroughSubject<String, Never>
}

这应该作为字符串的前缀,然后将任何更新发送到 Logger。有没有办法将一个 PassthroughSubject(例如 MyLogger)的输出链接到另一个(例如 Logger)?

我知道我可以这样做:

let cancellable = myLogger.log.sink { 
  logger.log.send("[MyApp] " + [=12=])
}

但是,这看起来不像是将事物链接在一起的组合方式。我希望有一个 API 我可以使用更类似于这个的:

logger.log.subscribe(myLogger.log.map { "[MyApp] " + [=13=] })

但是,这无法编译,因为我认为地图导致它变成了发布者而不是主题:

Instance method 'subscribe' requires that 'Publishers.Map<PassthroughSubject<String, Never>, String>' conform to 'Subject'

除了依赖 sink 之外,是否有更明确的 API 让一个 PassthroughSubject 订阅另一个(支持其间的突变)的更新?

如果您翻转订阅的顺序,它会起作用:

let cancellable = myLogger.log
  .map { "[MyApp] " + [=10=] }
  .subscribe(logger.log)

myLogger.send("test") // will send "[MyApp] test" to logger.log

话虽如此,像这样用 Combine 建模集 APIs 似乎有点奇怪,而且 Failure 数据类型似乎完全被忽略了。例如。如果日志失败,则无法将其失败的信息反馈给链。

更好的 API 可能是一个普通函数,returns 和 AnyPublisher:

class Logger {
  func log(_ string: String) -> AnyPublisher<Void, Never>
}

class MyLogger {
  func log(_ string: String) -> AnyPublisher<Void, Never> {
    return logger.log(string)
  }
}