对于包含参数数量的scala案例类(21 !!)
e.g。 case class Car(type: String, brand: String, door: Int ....)
其中type = jeep,brand = toyota,door = 4 .... etc
还有一种复制方法允许使用命名参数覆盖:Car.copy(brand = Kia)
哪里会变成type = jeep,brand =起亚,门= 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个参数的case类时,我不想重复21个参数赋值。
非常感谢!
答案 0 :(得分:3)
FWIW,我刚刚实现了Java反射版本:CaseClassCopy.scala。我尝试了TypeTag version,但它并没有用; 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]
}
}
答案 1 :(得分:0)
使用案例类是不可能的。
编译时生成的复制方法和编译时处理的命名参数。没有可能在运行时进行。
Dynamic
可能有助于解决您的问题:http://hacking-scala.tumblr.com/post/49051516694/introduction-to-type-dynamic
答案 2 :(得分:0)
是的,你需要使用反射来做到这一点。
有点涉及,因为copy
是一种合成方法,你必须为除了你想要替换的那个字段之外的所有字段调用getter。
为了给你一个想法,copy method in this class正是这样做的,除了使用参数索引而不是名称。它调用伴侣对象的apply
方法,但效果是一样的。
答案 3 :(得分:0)
我有点困惑 - 以下不是你需要的是什么?
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, ...)
您似乎了解这些功能,并认为它们不符合您的需求 - 您能解释一下原因吗?