2

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

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")
    }
)

它创建了一个 observable,其中前 10 个是CaseOne,接下来是CaseTwo。然后根据它们是偶数还是奇数对它们进行分组。Observable[(Long, Observable[MyCaseClass])]因此,根据 RX-Java 规范,分组的 observable 最终是 type 。

然而,当我们订阅一个 '​​groupedby' observable 时,类型擦除意味着嵌套的 Observable 的签名丢失了,即我们无法判断它是 CaseOne 还是 CaseTwo(它变成了 type Any) - 编译器会对此发出警告,所以输出是

Case one
Case one
Case one
...

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

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

还要注意,虽然我没有even在这个例子中使用,但它直接反映了我的问题的结构。

4

1 回答 1

1

请注意,结果中包含的所有 observables groupedObsareObservable[MyCaseClass] 和 not Observable[CaseOne] or 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")
    }
}

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

于 2014-03-04T13:38:27.950 回答