2011-09-13 124 views
2

我真的很喜欢使用上限类型边界来给我的结构可以采取一些灵活性。不过,我真的不知道它的任何背后的原理,因为我用下面的代码中找到:斯卡拉上限类型边界和父类

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 s与Service s不同?在这里可以参考Service还是不可能的?

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

回答

9

在Scala参数化类型默认情况下是不变的,例如,对于Cage[A] a Cage[Bird]不是 a Cage[Animal]。但是你可以通过方差声明进行类型协变甚至逆变换,例如Cage[+A](a: A),这是编译器试图告诉你的错误信息。

现在并不总是可以做出类型参数协变。这只有在类型变量仅用于所谓的正数发生时才有效。或者如果你的课程是不可变的,那就把另一个(不是100%正确的)方法。在你的情况下,它会起作用。因此,所有你需要做的就是添加一个+Library定义:

class Library[+T <: Service](collection: Collection[T], actives: Actives[T]) 
4

由于编译错误很有帮助说,类Library是不变的。那就是:

Library[S] <: Library[T] IFF S <: T

不成立。该属性被称为协方差并且是泛型类型参数的属性。这导致一个编译器错误的原因是你的地图预计Library[Service]作为它的值类型,您要添加一个Library[T](其中,因缺少协的,是不是Library[Service],即使T <: Service

如果您的Library类是不可变的,那么您应该能够将+添加到类型参数以指示scalac类型的协变。