考虑
trait Fruit {
val name: String
}
case class Apple(override val name: String) extends Fruit
case class Banana(override val name: String) extends Fruit
当我定义一个函数来仅收集特定类型时
def onlyT[T](list: List[Fruit]): List[T] = list.collect { { case x: T => x } }
def onlyT2[T: ClassTag](list: List[Fruit]): List[T] = list.collect { { case x: T => x } }
val fruitList: List[Fruit] = List(Apple("app1"), Apple("app2"), Apple("app3"), Apple("app4"), Banana("ban1"), Banana("ban2"), Banana("ban3"))
下面的
val a
属于 List[Banana]
类型,但包含 Apple
类型的条目。
scala
val a: List[Banana] = onlyT[Banana](fruitList)
val b: List[Banana] = fruitList.collect { case x: Banana => x }
val c: List[Banana] = onlyT2[Banana](fruitList)
println(a) // List(Apple(app1), Apple(app2), Apple(app3), Apple(app4), Banana(ban1), Banana(ban2), Banana(ban3))
println(b) // List(Banana(ban1), Banana(ban2), Banana(ban3))
println(c) // List(Banana(ban1), Banana(ban2), Banana(ban3))
这是预期的吗?或者它是一个类型系统错误?我知道在运行时类型被删除,但不确定为什么它适用于 b 而不是 a?我认为编译器不应该允许这样的情况。我缺少什么吗?
仅供参考,这不是一个解决问题的问题,我可以通过使用 ClassTag 来解决它
如果你了解类型擦除,答案很容易理解。
所以...在 Java 中,任何
F[T]
都被简化为 F[Object]
。
类似,你的方法
def onlyT[T](list: List[Fruit]): List[T]
实际上变成了def onlyT[Object](list: List[Fruit]): List[Object]
...所以方法主体list.collect { { case x: T => x } }
变成了list.collect { { case x: Object => x } }
。
这就是为什么所有东西都会通过过滤器。
在
fruitList.collect { case x: Banana => x }
的情况下不会发生此类擦除。