复制案例类并更改字段列表

时间:2019-01-17 14:27:27

标签: scala

是否有一种使用字段及其新值的映射在scala中复制案例类的方法?

我尝试了一种包含反射的方法,所以我想避免这种情况

def copyWithMap(fieldNameValue: Map[String, Option[AnyREF]]): T

应用于案例类时,应复制并更新需要更新的字段。 (在地图中指定)

2 个答案:

答案 0 :(得分:2)

如果要对任何通用对象执行此操作,则需要某种方式将字段的编译时名称映射到该字段在对象中的运行时位置。唯一的内置机制是反射,因此如果不使用反射(或实现自己的通用反射机制,这似乎毫无意义),您将无法做自己想要的事情。

答案 1 :(得分:2)

如果您知道在开始之前必须更新的内容,则可以执行以下操作:

scala> case class Person(name: String, age: Int, eyeColour: String)
defined class Person

scala> val p1 = Person("Bill", 24, "blue")
p1: Person = Person(Bill,24,blue)

scala> val p2 = p1.copy(name = "Ben", eyeColour = "brown")
p2: Person = Person(Ben,24,brown)

如果您想使其更通用,也许可以使用类似的方法(将setField取自Duncan McGregor's answer in the linked post并放入隐式类中):

implicit class Modify[T](i: T) {
  def modify(m: Map[String, Any]): T = {
    for ((name, value) <- m) setField(name, value)
    i
  }

  def setField(fieldName: String, fieldValue: Any) = {
    i.getClass.getDeclaredFields.find(_.getName == fieldName) match {
      case Some(field) =>
        field.setAccessible(true)
        field.set(i, fieldValue)
      case None =>
        throw new IllegalArgumentException(s"No field named $fieldName")
    }
  }
}

case class Person(name: String, age: Int, eyeColour: String)

val p1 = Person("Bill", 24, "blue")

val p2 = p1.copy().modify(Map("name" -> "Ben", "eyeColour" -> "brown"))
// p2: Person = Person(Ben,24,brown)

p1
// res0: Person = Person(Bill,24,blue)