我有以下课程:
trait Foo {
def update: Foo
}
class ConcreteFoo extends Foo {
override def update: Foo = new ConcreteFoo
}
class FooManager[T <: Foo](val foos: mutable.Map[String, T]) {
def update(id: String): Unit = {
foos.update(id, foos(id).update)
}
}
当然update
函数不编译:
类型失配发现Foo需要T
如何制作def update: Foo
协变?
答案 0 :(得分:3)
我建议改用不可变的地图。因为只有不可变集合可以有协变类型参数。
class FooManager[+T <: Foo](val foos: immutable.Map[String, T]) {
def update(id: String): FooManager[Foo] = {
new FooManager(foos.updated(id, foos(id).update))
}
}
答案 1 :(得分:2)
看起来你想要类似F-bounded多态的东西:
trait Foo[T <: Foo[T]] { self: T =>
def update: T
}
class ConcreteFoo extends Foo[ConcreteFoo] {
override def update = new ConcreteFoo
}
class FooManager[T <: Foo[T]](val foos: mutable.Map[String, T]) {
def update(id: String): Unit = {
foos.update(id, foos(id).update)
}
}
一种替代的,可能更简单的解决方案是使用不可变的Map
,正如Luka所说。但是那时不再需要类型参数了:
trait Foo {
def update: Foo
}
class ConcreteFoo extends Foo {
override def update: Foo = new ConcreteFoo
}
class FooManager(private var _foos: immutable.Map[String, Foo]) {
def foos = _foos
def update(id: String): Unit = {
_foos = _foos.updated(id, _foos(id).update)
}
}
您还可以保留当前的解决方案并删除type参数。但是,您有一些轻微的不便,即您无法将mutable.Map[String,ConcreteFoo]
传递给FooManager
的构造函数。