如何使方法返回类型协变

时间:2017-03-13 09:31:05

标签: scala

我有以下课程:

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协变?

2 个答案:

答案 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的构造函数。