Scala 分裂一个可观测的Monix

Scala 分裂一个可观测的Monix,scala,monix,Scala,Monix,我想为monix.reactive.Observable编写一个拆分函数。它应该根据谓词的值将源可观察[a]拆分为一对新的(可观察[a],可观察[a]),并对源中的每个元素进行评估。我希望拆分独立于观察到的源是热的还是冷的。在源为冷的情况下,新的一对观测值也应为冷,而在源为热的情况下,新的一对观测值将为热。我想知道这样的实现是否可行,如果可行,如何实现(我在下面粘贴了一个失败的测试用例) 签名作为隐式类上的方法,看起来类似于或类似于 /** *用谓词分割一个可观察对象,放置谓词返回true的值

我想为
monix.reactive.Observable
编写一个拆分函数。它应该根据谓词的值将源
可观察[a]
拆分为一对新的
(可观察[a],可观察[a])
,并对源中的每个元素进行评估。我希望拆分独立于观察到的源是热的还是冷的。在源为冷的情况下,新的一对观测值也应为冷,而在源为热的情况下,新的一对观测值将为热。我想知道这样的实现是否可行,如果可行,如何实现(我在下面粘贴了一个失败的测试用例)

签名作为隐式类上的方法,看起来类似于或类似于

/**
*用谓词分割一个可观察对象,放置谓词返回true的值
*右侧(以及谓词在左侧返回false的值)。
*这符合任何一方通过的公约。
*/
def split(p:T=>Boolean)(隐式调度器:调度器,taskLike:taskLike[Future]):(可观测[T],可观测[T])={
splitother[T,T](elem=>任一.cond(p(elem),elem,elem))
}
目前,我有一个简单的实现,它使用源元素并将它们推送到
PublishSubject
。因此,这对新的可见光非常热门。我的感冒测试失败了

导入monix.eval.TaskLike
导入monix.execution.{Ack,Scheduler}
导入monix.reactive.{可观察,观察者}
导入monix.reactive.subjects.PublishSubject
导入scala.concurrent.Future
观察对象{
隐式类ObservableExtensions[T](o:Observable[T]){
/**
*用谓词分割一个可观察对象,放置谓词返回true的值
*右侧(以及谓词在左侧返回false的值)。
*这符合任何一方通过的公约。
*/
def split(p:T=>Boolean)(隐式调度器:调度器,taskLike:taskLike[Future]):(可观测[T],可观测[T])={
splitother[T,T](elem=>任一.cond(p(elem),elem,elem))
}
/**
*将一个可观察对象拆分为一对可观察对象,一左一右,根据
*到行列式函数。
*/
def splitory[U,V](f:T=>or[U,V])(隐式调度器:调度器,taskLike:taskLike[Future]):(可观测[U],可观测[V])={
val l=出版主题[U]()
val r=出版主题[V]()
o、 订阅(新观察员[T]{
覆盖def onNext(元素:T):未来[Ack]={
f(elem)匹配{
案例左侧(u)=>l.onNext(u)
案例右侧(v)=>r.onNext(v)
}
}
覆盖def onError(例如:可丢弃):单位={
l、 onError(ex)
r、 onError(ex)
}
覆盖def onComplete():单位={
l、 onComplete()
r、 onComplete()
}
})
(左、右)
}
}
}
//////////
导入可观察的事件_
导入monix.execution.Scheduler.Implicits.global
导入monix.reactive.Observable
导入monix.reactive.subjects.PublishSubject
导入org.scalatest.FlatSpec
导入org.scalatest.Matchers_
导入org.scalatest.concurrent.ScalaFutures_
类observeOpsSpec扩展了FlatSpec{
val isEven:Int=>Boolean=%2==0
“可观察的行动”应“分割冷可观察的行动”{
val o=可观察(1,2,3,4,5)
val(l,r)=o.split(isEven)
l、 toListL.runToFuture.futureValue应为列表(1、3、5)
r、 toListL.runToFuture.futureValue应为列表(2,4)
}
“可观察的行动”应“分割热可观察的行动”{
val o=PublishSubject[Int]()
val(l,r)=o.split(isEven)
val lbuf=l.toListL.runToFuture
val rbuf=r.toListL.runToFuture
可观察的.fromIterable(1到5).mapEvalF(i=>o.onNext(i)).subscribe()
o、 onComplete()
lbuf.futureValue应为列表(1、3、5)
rbuf.futureValue应为列表(2,4)
}
}
我希望上面的两个测试用例都能通过,但是“可观察操作”应该“分割一个冷可观察操作”失败了

编辑:工作代码 通过两个测试用例的实现如下所示:

导入monix.execution.Scheduler
导入monix.reactive.Observable
观察对象{
隐式类ObservableExtension[T](o:Observable[T]){
/**
*用谓词分割一个可观察对象,放置谓词返回true的值
*右侧(以及谓词在左侧返回false的值)。
*这符合任何一方通过的公约。
*/
def拆分(
p:T=>Boolean
)(隐式调度程序:调度程序):(可观测[T],可观测[T])={
splitother[T,T](elem=>任一.cond(p(elem),elem,elem))
}
/**
*将一个可观察对象拆分为一对可观察对象,一左一右,根据
*到行列式函数。
*/
def拆分[U,V](
f:T=>任一[U,V]
)(隐式调度程序:调度程序):(可观测[U],可观测[V])={
val oo=o.map(f)
val l=oo.collect{
案例左侧(u)=>u
}
val r=oo.collect{
案例右侧(v)=>v
}
(左、右)
}
}
}

根据定义,Cold observable对每个订阅者进行延迟评估。如果不对所有内容进行两次评估或将其转换为热门内容,则无法将其拆分

如果您不介意对所有内容进行两次评估,只需使用
.filter
两次即可。 如果您不介意转换为hot,请使用
.publish
(或
.publish.refCount
,这样您就不需要手动连接
)。
如果您想保留冷/热属性并并行处理两个部分,有一种
publishSelector
方法可以让您在有限的范围内将任何可观察到的视为热的:

coldOrHot.publishSelector{totallyHot=>
val s1=TotalyHot.filter(…).flatMap
class ObservableOpsSpec extends FlatSpec {

  val isEven: Int => Boolean = _ % 2 == 0

  "Observable Ops" should "split a cold observable" in {
    val o = Observable(1, 2, 3, 4, 5)
   val o2 =  o.publish
    val (l, r) = o2.split(isEven)

  val x=   l.toListL.runToFuture
  val y =   r.toListL.runToFuture
    o2.connect()
    x.futureValue shouldBe List(1, 3, 5)
    y.futureValue shouldBe List(2, 4)
  }

  "Observable Ops" should "split a hot observable" in {
    val o = PublishSubject[Int]()

    val (l, r) = o.split(isEven)
    val lbuf = l.toListL.runToFuture
    val rbuf = r.toListL.runToFuture

    Observable.fromIterable(1 to 5).mapEvalF(i => o.onNext(i)).subscribe()
    o.onComplete()

    lbuf.futureValue shouldBe List(1, 3, 5)
    rbuf.futureValue shouldBe List(2, 4)
  }
}