我真的很喜欢使用上层类型边界来为我的构造提供一些灵活性。但是,我真的不知道它背后的任何原理,因为我发现使用以下代码:
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
或者这是不可能的?
还是我完全吠叫错了树?谢谢!
答案 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]
iffS <: T
不成立。此属性称为协方差,是泛型类型参数的属性。这导致编译器错误的原因是您的地图期望Library[Service]
作为其值类型,并且您尝试添加Library[T]
(由于缺乏协方差,它不是Library[Service]
1}},即使T <: Service
)
如果您的Library
类是不可变的,那么您应该能够在type参数中添加+
,以向scalac
表明库是协变在它的类型。