考虑这个(人为的)代码:
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
,但它直接反映了我的问题的结构。
答案 0 :(得分:1)
请注意,groupedObs
的结果中包含的所有可观察对象都是Observable[MyCaseClass]
,而不是 Observable[CaseOne]
或Observable[CaseTwo]
。因此,如果没有删除并且类型检查 工作,那么您将获得MatchError
。事实上,在您的情况下,每个键下的可观察量将包括CaseOne
和CaseTwo
元素。
所以是的,您需要包含额外的数据。你有两个选择。
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")
}
}
这将打印原始可观察元素的每个元素的输出;或者,您可以在第一个元素之后停止(例如,因为您知道同一个键的所有元素具有相同的类)等等。