处理groupBy中嵌套Observable的类型擦除

时间:2014-03-04 09:02:43

标签: scala rx-java

考虑这个(人为的)代码:

sealed abstract class MyCaseClass(val num : Long)
case class CaseOne(override val num : Long) extends MyCaseClass(num)
case class CaseTwo(override val num : Long) extends MyCaseClass(num)

val groupedObs : Observable[(Long, Observable[MyCaseClass])] =
    Observable(1 to 20) map {
      x => if (x > 10) CaseOne(x) else CaseTwo(x)
  } groupBy {
    case CaseOne(x) => x % 2 == 0
    case CaseTwo(x) => x % 2 == 0
  }

groupedObs subscribe ( (onNext : (Long,Observable[MyCaseClass])) => onNext match {
        case (even : Boolean, o : Observable[CaseOne] ) => println("Case one")
        case (even : Boolean, o : Observable[CaseTwo] ) => println("Case two")
    }
)

它会创建一个可观察的,其中前10个是CaseOne,下一个是CaseTwo。然后它将它们分组为偶数还是奇数。因此,根据RX-Java规范,分组的observable最终为Observable[(Long, Observable[MyCaseClass])]类型。

但是,当我们订阅'groupsby'可观察时,类型擦除意味着嵌套的Observable的签名丢失,即我们无法判断它是CaseOne还是CaseTwo(它变成类型Any ) - 编译器会对此发出警告,因此输出为

Case one
Case one
Case one
...

我的问题是,在上面的场景中,你如何处理嵌套的Observable的类型擦除?

到目前为止,我唯一的解决方法是在密钥中包含一个额外的值,用于标识嵌套的Observable类型,然后将(使用asInstance)强制转换为此类型。但这不是很好。

另请注意,虽然我在此示例中不使用even,但它直接反映了我的问题的结构。

1 个答案:

答案 0 :(得分:1)

请注意,groupedObs的结果中包含的所有可观察对象都是Observable[MyCaseClass] ,而不是 Observable[CaseOne]Observable[CaseTwo]。因此,如果没有删除并且类型检查 工作,那么您将获得MatchError。事实上,在您的情况下,每个键下的可观察量将包括CaseOneCaseTwo元素。

所以是的,您需要包含额外的数据。你有两个选择。

1)使类成为密钥的一部分:

val groupedObs : Observable[((Boolean, Class[_]), Observable[MyCaseClass])] =
    Observable(1 to 20) map {
      x => if (x > 10) CaseOne(x) else CaseTwo(x)
  } groupBy {
    case CaseOne(x) => (x % 2 == 0, classOf[CaseOne])
    case CaseTwo(x) => (x % 2 == 0, classOf[CaseTwo])
  }

groupedObs subscribe ( (onNext : ((Boolean, Class[_]), Observable[MyCaseClass])) => onNext match {
        case ((even : Boolean, c: Class[_]), o : Observable[_]) if c == classOf[CaseOne] => println("Case one")
        case ((even : Boolean, c: Class[_]), o : Observable[_]) if c == classOf[CaseTwo] => println("Case two")
    }
)

2)检查嵌套observable的元素:

// groupedObs as in your code, not as above
groupedObs subscribe {
  case (even : Boolean, o : Observable[MyCaseClass] ) => 
    o subscribe { 
      case _: CaseOne => println("Case one")
      case _: CaseTwo => println("Case two")
    }
}

这将打印原始可观察元素的每个元素的输出;或者,您可以在第一个元素之后停止(例如,因为您知道同一个键的所有元素具有相同的类)等等。