2011-09-13 54 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類型的協變。