协方差类型的泛型函数输出是错误的,这是类型系统错误还是预期的?

问题描述 投票:0回答:1

考虑

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 来解决它

scala type-erasure type-systems
1个回答
0
投票

如果你了解类型擦除,答案很容易理解。

所以...在 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 }
的情况下不会发生此类擦除。

© www.soinside.com 2019 - 2024. All rights reserved.