在父类中创建新实例时保留亚型(Preserving subtypes when creating n

2019-10-20 03:01发布

我有以下的(简化)类,包装了一个Map

class Store(val values: Map[String, String]) {
  def set(name: String, value: String): Store = new Store(values + (name -> value))
  def remove(name: String): Store = new Store(values - name)
}

我想有其他类扩展为覆盖,也就是说, toString方法:

class PrintableStore(values: Map[String, String]) extends Store(values) {
  override def toString: String = values.toString
}

这个问题,在事后很明显,是setremove的回报情况Store :这些方法的返回值是类型不正确,和我失去我的增强toString方法。

我能找到的唯一的解决办法是定义Store与自我类型特点如下:

trait Store[+Self] {
  this: Self =>

  def values: Map[String, String]
  def copy(values: Map[String, String]): Self

  def set(name: String, value: String): Self = copy(values + (name -> value))
  def remove(name: String): Self = copy(values - name)

}

class PrintableStore(val values: Map[String, String]) extends Store[PrintableStore] {
  override def toString: String = values.toString
  override def copy(values: Map[String, String]): PrintableStore = new PrintableStore(values)
}

这工作得很好,但需要什么,我觉得是对样板Scala代码数量惊人的:

  • 所有子类都将有一个实现copy是基本相同的。
  • 所有子类都将始终通过自己作为参数类型Store

有没有更好的解决这个问题,还是我宠坏了,我的样板门槛太低? 我必须承认,虽然我觉得我了解自己的类型,我不能完全自如地使用他们又和以前的代码很可能是完全不正确。

Answer 1:

你可以做同样的事情的集合库做什么:

trait StoreLike[T <: StoreLike[T]] {
  val values: Map[String, String]
  def set(name: String, value: String): T = build(values + (name -> value))
  def remove(name: String): T = build(values - name)
  def build(values: Map[String, String]): T
}

class Store(val values: Map[String, String]) extends StoreLike[Store] {
  def build(values: Map[String, String]): Store = new Store(values)
}

class PrintableStore(val values: Map[String, String]) extends StoreLike[PrintableStore] {
  override def toString: String = values.toString()
  def build(values: Map[String, String]): PrintableStore = new PrintableStore(values)
}


文章来源: Preserving subtypes when creating new instances in the parent class
标签: scala