3

对于具有参数数量的scala案例类(21!!)

例如case class Car(type: String, brand: String, door: Int ....) ,type = jeep,brand = toyota,door = 4 ....etc

还有一种复制方法允许使用命名参数进行覆盖:Car.copy(brand = Kia) 其中将变为 type = jeep、brand = Kia、door = 2...等

我的问题是,无论如何我可以动态提供命名参数吗?

def copyCar(key: String, name: String) = {
  Car.copy("key" = "name") // this is something I make up and want to see if would work
}

scala反射库可以在这里提供帮助吗?

我使用复制方法的原因是我不想每次创建一个只更改了 1 或 2 个参数的案例类时都重复 21 个参数分配。

非常感谢!

4

4 回答 4

3

FWIW,我刚刚实现了一个 Java 反射版本:CaseClassCopy.scala。我尝试了一个TypeTag 版本,但它没有那么有用;为此目的,TypeTag 过于严格。

  def copy(o: AnyRef, vals: (String, Any)*) = {
    val copier = new Copier(o.getClass)
    copier(o, vals: _*)
  }

  /**
   * Utility class for providing copying of a designated case class with minimal overhead.
   */
  class Copier(cls: Class[_]) {
    private val ctor = cls.getConstructors.apply(0)
    private val getters = cls.getDeclaredFields
      .filter {
      f =>
        val m = f.getModifiers
        Modifier.isPrivate(m) && Modifier.isFinal(m) && !Modifier.isStatic(m)
    }
      .take(ctor.getParameterTypes.size)
      .map(f => cls.getMethod(f.getName))

    /**
     * A reflective, non-generic version of case class copying.
     */
    def apply[T](o: T, vals: (String, Any)*): T = {
      val byIx = vals.map {
        case (name, value) =>
          val ix = getters.indexWhere(_.getName == name)
          if (ix < 0) throw new IllegalArgumentException("Unknown field: " + name)
          (ix, value.asInstanceOf[Object])
      }.toMap

      val args = (0 until getters.size).map {
        i =>
          byIx.get(i)
            .getOrElse(getters(i).invoke(o))
      }
      ctor.newInstance(args: _*).asInstanceOf[T]
    }
  }
于 2014-05-14T02:49:12.000 回答
0

不可能使用案例类。

将编译时生成的方法和编译时处理的命名参数复制到。在运行时不可能做到这一点。

Dynamic可能有助于解决您的问题:http ://hacking-scala.tumblr.com/post/49051516694/introduction-to-type-dynamic

于 2013-06-26T06:40:53.720 回答
0

是的,您需要使用反射来做到这一点。

它有点复杂,因为它copy是一种合成方法,您必须为所有字段调用 getter,但要替换的字段除外。

给你一个想法,这个类中的复制方法正是这样做的,除了使用参数索引而不是名称。它调用伴生对象的apply方法,但效果是一样的。

于 2013-06-28T14:56:26.130 回答
-1

我有点困惑 - 以下内容怎么不是你需要的?

car: Car = ...          // Retrieve an instance of Car somehow.
car.copy(type = "jeep") // Copied instance, only the type has been changed.
car.copy(door = 4)      // Copied instance, only the number of doors has changed.
// ...

是因为你有很多初始实例创建的参数吗?在这种情况下,您可以不使用默认值吗?

case class Car(type: String = "Jeep", door: Int = 4, ...)

您似乎了解这两个功能,但觉得它们不符合您的需要 - 您能解释一下原因吗?

于 2013-06-28T15:24:02.873 回答