考虑
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
。
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 无效?我认为如果情况如此,编译器不应该允许 a。我遗漏了什么吗?
仅供参考,这不是一个解决问题的问题,我可以使用 ClassTag 解决它。问题是:为什么 Scala 编译器允许类型声明val a: List[Banana]
,而我们最终得到了一个类型为苹果和香蕉的列表List[Banana]
如果您理解类型擦除,那么答案就很容易理解。
所以...在 Java 中,any在运行时
F[T]
被简化为F[Object]
。类似你的方法
实际上简化为
这就是为什么当您调用时所有内容都会通过过滤器
onlyT[Banana](fruitList)
。在 的情况下,不会发生此类擦除
fruitList.collect { case x: Banana => x }
。