Scala 结构类型,其方法只有一些参数是已知的

Scala structural type with method where only some params are known

鉴于此代码:

object Testy extends App {

  case class Person(
                     id: Option[Long],
                     firstName: String,
                     lastName: String,
                     address: Address)

  case class Address(id: Option[Long],
                     name: String,
                     number: Int)

  val personOrAddress:AnyRef= Person(Some(1L), "first", "last", Address(Some(1L), "street", 1))
  type HasCopyMethodWithId = _
  val newId = Some(123L)
  personOrAddress.asInstanceOf[HasCopyMethodWithId].copy(id = newId)
}

我如何实现 'type HasCopyMethodWithId' 以便此代码编译并且不会在运行时失败?

我试过:

type HasCopyMethodWithId = {def copy(id: Option[Long]): AnyRef}

case classes 提供的合成 copy 方法是 一个单一 方法,其中包含该 case class 的所有参数,而不是一个个人为idfirstName等重载了一个。因此结构类型不匹配。

您可以添加辅助方法:

case class Person(id: Option[Long],
                  firstName: String,
                  lastName: String,
                  address: Address) {

  def copyId(newId: Option[Long]): Person = copy(id = newId)
}

case class Address(id: Option[Long],
                   name: String,
                   number: Int) {
  def copyId(newId: Option[Long]): Address = copy(id = newId)
}

val personOrAddress: Any = 
  Person(Some(1L), "first", "last", Address(Some(1L), "street", 1))

type HasCopyMethodWithId = { def copyId(id: Option[Long]): Any }
val newId = Some(123L)
personOrAddress.asInstanceOf[HasCopyMethodWithId].copyId(id = newId)

但几乎可以肯定的是提供静态类型更好:

trait CopyWithId { 
  type Repr 
  def copyId(id: Option[Long]): Repr
}

case class Person(id: Option[Long],
                  firstName: String,
                  lastName: String,
                  address: Address) extends CopyWithId {

  type Repr = Person
  def copyId(newId: Option[Long]): Person = copy(id = newId)
}

case class Address(id: Option[Long],
                   name: String,
                   number: Int) extends CopyWithId {

  type Repr = Address
  def copyId(newId: Option[Long]): Address = copy(id = newId)
}

val personOrAddress: CopyWithId = 
  Person(Some(1L), "first", "last", Address(Some(1L), "street", 1))

val newId = Some(123L)
personOrAddress.copyId(id = newId)