如果Scala还有子类型,Scala中存在存在性是否有任何有意义的原因?
例如,在Haskell中,existentials可用于异构lists,但在Scala中,异构列表只需使用子类型即可创建。
这让我想知道如果Scala中存在子类型,为什么有人会想要使用存在?是否有任何用于存在的用例,通过子类型无法更方便地解决?我不确定有没有。任何反例?
编辑:存在对于定义更高级的类型(Functor,Monad等)非常有用,我理解,但除此之外,还有其他有意义的用例吗?答案 0 :(得分:2)
我工作项目中存在的例子:
实施类型安全参数存储
trait Parameter[T] // T is a type of a value related to this parameter
trait ParameterStorage {
def getValue[T](p: Parameter[T]): Option[T]
}
//implementation
type ParamAndValue = (Parameter[T], T) forSome { type T; }
//initialize storage with pairs of parameters and values
class StorageImpl(pairs: ParamAndValue*) {
...
}
答案 1 :(得分:1)
考虑例如Array[_]
。它与Array[Any]
完全相同,例如
val x: Array[Any] = new Array[Any](5)
x(0) = "" // legal
val y: Array[_] = new Array[Double](5)
y(0) = "" // illegal
编辑:存在对于定义更高级的类型(Functor,Monad等)非常有用,我理解,但除此之外,还有其他有意义的用例吗?
没有。 F[_]
中的Functor[F[_]]
看起来与存在主义相同,但根本不是。
答案 2 :(得分:0)
这是刚才出现的一个例子:
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协变,那么我需要在这里使用存在感。
换句话说,存在性可用于在更精细的分辨率中设置协方差,例如在上面显示的方法级别上,而不是通过将其声明为RefVal[+T<:Entity]
来全局设置RefVal协变。
EDIT2:
以下是存在感的其他一些有用用法:
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]]
但是这可能会使很多事情变得混乱,协变+注释可以感染大部分代码,其中没有那些协变的东西很重要。因此,保持事物不变并在一个地方(在存储对象的集合中)使用存在性可能比使用协方差注释乱丢代码更简单。