【问题标题】:Scala generic types and covariance/contravarianceScala 泛型类型和协变/逆变
【发布时间】:2013-11-29 18:25:22
【问题描述】:

我想我已经了解协方差和协方差的原理。但是似乎我在使用它时仍然遇到问题。 这是一个例子:我想编写一个简单的通用不可变容器,它具有一组固定的值。 所以我创建了一个基本的 Trait

trait Container[+A] {

 type B <: A

 def add(elem: B): Container[A]
} 

然后我开始编写具体的类来表示具有不同数量值的不同容器,例如一个空容器和一个具有一个元素的容器

class Container0[+A] extends Container[A] {

  def add(elem: B): Container[A] = new Container1[A](elem)
}  


class Container1[+A](elem0: A) extends Container[A] {

 def add(elem: B): Container[A] = new Container2[A](elem0, elem)
}

这编译得很好,但是当我尝试使用它时:

var t: Container[AnyVal] = new Container0[AnyVal]
t = t.add(5)

我收到以下错误:

type mismatch; found : Int(5) required: _3.B where val _3: Container[AnyVal]

【问题讨论】:

  • 试试trait Container[+A] { def add[B &gt;: A](elem: B): Container[B] }
  • _3.B 类型是路径相关类型。当你在你的 trait 定义中说 type B &lt;: A 时,你实际上是在说 B 可以在每个 Container 的实例中有所不同。编译器无法知道Int与t的当前值的特定类型B兼容。
  • 使用 B >:A 没有解决问题:现在它的类型不匹配;找到:Container[_50.B] where val _50: Container[AnyVal] required: Container[AnyVal]
  • 你正试图改变一个不可变的容器。
  • 你能指出哪里吗? add 的返回类型是一个容器,所以我创建了一个全新的容器实例,它是前一个容器的副本 + 应该添加的元素。我认为这正是不可变的工作原理

标签: scala generics covariance


【解决方案1】:

Container 中的类型 B 在 Container 的类型中不可见。所以对于add,我们只知道它要求它的参数是某种类型的B,这可能比A 更具体,但我们不知道B 是什么。所以不可能调用add(这就是错误信息如此奇怪的原因)。

你想用type B做什么?

【讨论】:

  • 对于 B 类型,我想说它可以采用任何属于 A 子类型的元素。因此 B <: a>
  • 您实际上是在说“存在一个我可以接受的 B”,而不是“对于所有 B :def add[B :< A](elem: B): Container[A]。但实际上,这是不必要的,因为您只需 def add(elem: A): Container[A] 即可得到您想要的。
  • 我猜你在这样做之后还没有尝试过: def add(elem: A): Container[A] 给你留下错误:协变类型 A 出现在值 elem 的类型 A 中的逆变位置
  • @norathem 哦,对了,我忘记了协方差。那么应该是def add[B &gt;: A](elem: B): Container[B]。所以你会得到一个可能更宽松的集合。
  • 感谢您的帮助。我的问题是我试图在顶部定义类型 B 但这不起作用。我必须在每个使用它的方法中声明它。
猜你喜欢
  • 1970-01-01
  • 2020-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-27
  • 2011-02-02
相关资源
最近更新 更多