繁体   English   中英

Scala中的存在性与协方差

[英]Existentials vs Covariance in Scala

考虑下面的两个代码。 他们实现了同样的目标:只有这样的A[T] -s可以存储在T扩展CContainer

但是,他们使用两种不同的方法来实现这一目标:

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的回答):

评论说:“我对第二种解决方案的问题在于,它不应该成为描述我可以存储在容器中的东西的责任,而不是什么,这应该是容器的责任。”

如果我有class A[T](var t:T) ,这意味着我只能在容器中,在任何容器中存储A[T] -s而不能存储( A[S] ,其中S<:T )。

但是如果我有class A[+T](var t:T)那么我可以在任何容器中存储A[S] ,其中S<:T

因此,当声明A要么是不变量还是协变量时,我决定将哪种类型的A [S]存储在容器中(如上所示),这个决定发生在A的声明中。

但是,我认为,这个决定应该在容器的声明中进行,因为它是容器特定的,将允许进入该容器,只有A[T] -s或A[S]其中S<:T -s。

换句话说,更改A[T]的方差具有全局效果,而将容器的类型参数从A[T]更改为A[_<:S]对容器本身具有明确定义的局部效果。 因此,“改变应具有局部效应”的原则也有利于存在性解决方案。

在第一种情况下, A更简单,但在第二种情况下,它的客户端是。 由于通常有多个地方使用A ,这通常是值得的权衡。 您自己的代码演示了它:当您需要在第一种情况下(在两个地方)编写A[_ <: C]时,您可以在第二种情况下使用A[C]

另外,在第一种情况下,你可以只写A[C] ,其中A[_ <: C]是真正需要的。 假设你有一个方法

def foo(x: A[C]): C = x.t

现在你不能用y: A[C1]调用foo(y) y: A[C1]即使它有意义: yt确实有类型C

如果在您的代码中发生这种情况,它可以修复,但第三方呢?

当然,这也适用于标准库类型:如果像MaybeList这样的类型不是协变的,那么所有采用/返回它们的方法的签名都必须更复杂,或者许多程序当前都是有效的并且具有完美意义会打破。

它不应该是描述我可以存储在Container中的内容的责任,而不应该是Container的责任。

差异不是关于你可以存放在容器中的东西; 它是关于A[B]A[C]的子类型。 这个论点有点像说你根本不应该extends :否则class Apple extends Fruit允许你将Apple存储在Container[Fruit] ,并决定Container责任。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM