【发布时间】:2017-09-04 05:42:32
【问题描述】:
考虑下面的两个代码。他们实现了相同的目标:只有这样的A[T]-s 可以存储在Container 中,其中T 扩展C
然而,他们使用两种不同的方法来实现这一目标:
1) 存在主义
2) 协方差
我更喜欢第一个解决方案,因为这样A 仍然更简单。我有什么理由想要使用第二种解决方案(协方差)?
我对第二种解决方案的问题是它不自然,因为它不应该是A-s 的责任来描述我可以在 Container 中存储什么而不是什么,应该是Container的责任。第二种解决方案也更复杂,一旦我想开始对A 进行操作,然后我必须处理所有与协方差相关的东西。
使用第二种(更复杂、更不自然)的解决方案有什么好处?
object Existentials extends App {
class A[T](var t:T)
class C
class C1 extends C
class C2 extends C
class Z
class Container[T]{
var t:T = _
}
val c=new Container[A[_<:C]]()
c.t=new A(new C)
// c.t=new Z // not compile
val r: A[_ <: C] = c.t
println(r)
}
object Cov extends App{
class A[+T](val t:T)
class C
class C1 extends C
class C2 extends C
class Z
class Container[T]{
var t:T = _
}
val c: Container[A[C]] =new Container[A[C]]()
c.t=new A(new C)
//c.t=new A(new Z) // not compile
val r: A[C] = c.t
println(r)
}
编辑(回应 Alexey 的回答):
评论: “我对第二种解决方案的问题是,从某种意义上说,描述我可以存储在 Container 中的内容和不能存储的内容不应该是 Container 的责任,这是不自然的。”
如果我有class A[T](var t:T),这意味着我只能在容器中存储A[T]-s 而不能(A[S] where S<:T)在任何容器中。
但是,如果我有class A[+T](var t:T),那么我可以将A[S] 存储在S<:T 的任何容器中。
因此,当声明A 是不变的或协变的时,我决定可以将哪种类型的 A[S] 存储在容器中(如上所示),此决定发生在 A 的声明中。
但是,我认为,这个决定应该在容器的声明中进行,因为它是特定于容器的,允许进入该容器的只有 A[T]-s 或 A[S] where @ 987654340@-s。
换句话说,更改A[T] 中的方差会产生全局影响,而将容器的类型参数从A[T] 更改为A[_<:S] 会对容器本身产生明确的局部影响。所以这里的“变化应该有局部影响”的原则也有利于存在主义的解决方案。
【问题讨论】:
标签: scala covariance existential-type