Return 扩展特征的案例 class

Return a case class that extends a trait

我需要为 return 定义一个扩展特征的案例 class:

trait Id {
  def id: Long
}

case class Person(name: String)

val john = Person("John") 
val johnWithId: Person with Id = /*person -> 123L*/ ???

知道如何实现吗?

我正在努力减少代码的重复,这就是为什么我没有像这样声明一个特征 Person 的原因:

trait Id {
  def id: Long
}

trait Person {
  def name: String
}

case class PersonWithoutId(name: String) extends Person

case class PersonWithId(name: String, id: Long) extends Person with Id

val john = PersonWithoutId("John")
val johnWithId: Person with Id = PersonWithId(person.name, 123L)

知道如何实现吗?

val johnWithId: Person with Id = new Person("John") with Id { def id = 123L }

一旦 Person 已经实例化,就太晚了 - 您无法在实例化后更改实例 john。但是,您可以实例化 Person with Id:

val johnWithId: Person with Id = new Person("John") with Id {
  override def id: Long = 123L
}

请注意,这实际上 等同于 使用 PersonWithId(name: String, id: Long) 案例 class,例如 - equalshashcode 忽略 此实现中的 ID。

有点迂回:

case class WithId[A](id: Long, value: A) extends Id
object WithId {
  implicit def getValue[A](x: WithId[A]): A = x.value
}

// elsewhere
val johnWithId = WithId(123, john)

johnWithId 不会扩展 Person(因此 johnWithId.isInstanceOf[Person] 是错误的),但仍然可以在需要 Person 和 [=15= 的地方使用].

最正确的解决方案是

case class Person(name: String, id: Long) extends Id

理论上你可以做到

val johnWithId: Person with Id = new Person("John") with Id { def id = 123L }

如 Andrey 所述,它不会遵守整个 case class 合同,因为具有不同 ID 和相同姓名的人是平等的,因为 id 不会用于 equals 方法