这是一个刚刚出现的例子:
object Test{
trait Entity
case class SEntity() extends Entity
case class RefVal[T<:Entity](a:T)
def g(o:RefVal[Entity])= ???
def g2(o:RefVal[_<:Entity])= ???
g(RefVal[SEntity](a=SEntity())) // does not compile
g2(RefVal[SEntity](a=SEntity())) // does compile
}
如果我想避免使 RefVal 协变,那么我需要在这里使用存在主义。
换句话说,existentials 对于以更细粒度的分辨率设置协方差很有用,例如在方法级别上,如上所示,而不是通过将 RefVal 协变量声明为全局设置它RefVal[+T<:Entity]
。
编辑2:
下面是一些其他有用的existentials用法:
object Existentials_List extends App {
class A[T]
class J
class C1() extends J
class C2() extends J
class Z
val l: Set[A[_ <: J]] = Set()
val l2: Set[A[_ <: J]] = l + new A[J]
val l3: Set[A[_ <: J]] = l + new A[C1]
val l4: Set[A[_ <: J]] = l + new A[Z] // does not compile
}
其他可能性是制作 class A[+T]
并只是做Set[A[J]]
,但这会使很多事情变得混乱,协变 + 注释可以感染大部分代码,而这些协变的东西根本不重要。因此,保持事物不变并在一个地方(在存储对象的集合中)使用存在可能是一种比使用协方差注释乱扔代码更简单的解决方案。