Scala上层类型边界和父类

时间:2011-09-13 08:43:30

标签: scala types type-bounds

我真的很喜欢使用上层类型边界来为我的构造提供一些灵活性。但是,我真的不知道它背后的任何原理,因为我发现使用以下代码:

object BoundsTest {
  abstract trait Service
  class Collection[T <: Service] extends collection.mutable.HashMap[Symbol, collection.mutable.Set[T]] with collection.mutable.MultiMap[Symbol, T]
  type Actives[T <: Service] = collection.mutable.HashMap[Symbol, T]
  class Library[T <: Service](collection: Collection[T], actives: Actives[T])
  private val libraries = new collection.mutable.HashMap[Symbol, Library[Service]]
  def setLibrary[T <: Service](name: Symbol, library: Library[T]) {
    libraries += name -> library
  }
}

我试图让我的类可以使用Service的子类,只要它是一致的。但是,这不起作用:

$ scalac test.scala 
test.scala:10: error: type mismatch;
 found   : com.bubblefoundry.BoundsTest.Library[T]
 required: com.bubblefoundry.BoundsTest.Library[com.bubblefoundry.BoundsTest.Service]
Note: T <: com.bubblefoundry.BoundsTest.Service, but class Library is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
    libraries += name -> library
                         ^

问题是,我认为,我定义libraries的方式(以及何时?),好像我做了以下更改,所有内容都成功编译:

// private val libraries = new collection.mutable.HashMap[Symbol, Library[Service]]
def setLibrary[T <: Service](name: Symbol, library: Library[T]) {
  new collection.mutable.HashMap[Symbol, Library[T]] += name -> library
}

如何声明libraries HashMap,使其具有多个Library个不同的Service s?是否可以在这里引用Service或者这是不可能的?

还是我完全吠叫错了树?谢谢!

2 个答案:

答案 0 :(得分:9)

在Scala中,参数化类型默认是不变的,例如对于Cage[A]Cage[Bird] a Cage[Animal]。但是你可以通过方差声明来制作类型协变甚至逆变,例如: Cage[+A](a: A),这是编译器尝试在错误消息中告诉您的内容。

现在并不总是可以使类型参数协变。这仅在类型变量仅用于所谓的正面事件时才有效。如果你的类是不可变的,那么换一种方法(不是100%正确)。在你的情况下,它会工作。因此,您只需在+

的定义中添加Library即可
class Library[+T <: Service](collection: Collection[T], actives: Actives[T])

答案 1 :(得分:4)

正如编译错误所说,类Library是不变的。那就是:

  

Library[S] <: Library[T] iff S <: T

不成立。此属性称为协方差,是泛型类型参数的属性。这导致编译器错误的原因是您的地图期望Library[Service]作为其值类型,并且您尝试添加Library[T](由于缺乏协方差,它不是Library[Service] 1}},即使T <: Service

如果您的Library类是不可变的,那么您应该能够在type参数中添加+,以向scalac表明库协变在它的类型。