如果你有一个案例类,如:
case class Foo(x: String, y: String, z: String)
你有这样两种情况:
Foo("x1","y1","z1")
Foo("x2","y2","z2")
是否有可能在实例2合并实例1,除了Z区域,这样的结果将是:
Foo("x1","y1","z2")
我的用例就是我给JSON通过斯卡拉API对象为骨干的应用程序,而且支持骨干应用程序,让我回一个JSON结构相同的,这样我可以保存/更新。 这些JSON对象被解析为案例类,便于操控斯卡拉。 但有些领域不应该由客户端(如creationDate)进行更新。 现在我正在做一个手动合并,但我想更通用的解决方案,有点像一个增强的复制功能。
我想是这样的:
instanceFromDB.updateWith(instanceFromBackbone, excludeFields = "creationDate" )
但我想它是类型安全的:)
编辑:我的情况下,类有更多的领域,我想默认bevavior合并域,除非我明确地说,不合并。
Answer 1:
你需要的是已经存在; 你只需要解决这个问题的另一种方式。
case class Bar(x: String, y: String)
val b1 = Bar("old", "tired")
val b2 = Bar("new", "fresh")
如果你想在一切b2
未明确注明,则应该从复制b2
; 从任何b1
你要保持你可以明确地提及:
def keepY(b1: Bar, b2: Bar) = b2.copy(y = b1.y)
scala> keepY(b1, b2)
res1: Bar = Bar(new,tired)
只要你在同一案件类的两个实例之间的复制,栏是不可变的像他们在默认情况下,这会做你想要什么。
Answer 2:
case class Foo(x: String, y: String, z: String)
Foo("old_x", "old_y", "old_z")
// res0: Foo = Foo(old_x,old_y,old_z)
Foo("new_x", "new_y", "new_z")
// res1: Foo = Foo(new_x,new_y,new_z)
// use copy() ...
res0.copy(res1.x, res1.y)
// res2: Foo = Foo(new_x,new_y,old_z)
// ... with by-name parameters
res0.copy(y = res1.y)
// res3: Foo = Foo(old_x,new_y,old_z)
Answer 3:
您可以通过钻营排除了由复制方法复制自动类PARAMS:
case class Person(name: String, age: Int)(val create: Long, val id: Int)
这清楚哪些是普通值字段该客户端设置,哪些是特殊领域。 你可以不小心忘了提供一个特殊的领域。
对于采取从一个实例的值字段,并从另一个特殊字段,通过反思调用拷贝,无论是默认ARGS或原始的特殊成员用例:
import scala.reflect._
import scala.reflect.runtime.{ currentMirror => cm }
import scala.reflect.runtime.universe._
import System.{ currentTimeMillis => now }
case class Person(name: String, age: Int = 18)(val create: Long = now, val id: Int = Person.nextId) {
require(name != null)
require(age >= 18)
}
object Person {
private val ns = new java.util.concurrent.atomic.AtomicInteger
def nextId = ns.getAndIncrement()
}
object Test extends App {
/** Copy of value with non-defaulting args from model. */
implicit class Copier[A: ClassTag : TypeTag](val value: A) {
def copyFrom(model: A): A = {
val valueMirror = cm reflect value
val modelMirror = cm reflect model
val name = "copy"
val copy = (typeOf[A] member TermName(name)).asMethod
// either defarg or default val for type of p
def valueFor(p: Symbol, i: Int): Any = {
val defarg = typeOf[A] member TermName(s"$name$$default$$${i+1}")
if (defarg != NoSymbol) {
println(s"default $defarg")
(valueMirror reflectMethod defarg.asMethod)()
} else {
println(s"def val for $p")
val pmethod = typeOf[A] member p.name
if (pmethod != NoSymbol) (modelMirror reflectMethod pmethod.asMethod)()
else throw new RuntimeException("No $p on model")
}
}
val args = (for (ps <- copy.paramss; p <- ps) yield p).zipWithIndex map (p => valueFor(p._1,p._2))
(valueMirror reflectMethod copy)(args: _*).asInstanceOf[A]
}
}
val customer = Person("Bob")()
val updated = Person("Bobby", 37)(id = -1)
val merged = updated.copyFrom(customer)
assert(merged.create == customer.create)
assert(merged.id == customer.id)
}
Answer 4:
case class Foo(x: String, y: String, z: String)
val foo1 = Foo("x1", "y1", "z1")
val foo2 = Foo("x2", "y2", "z2")
val mergedFoo = foo1.copy(z = foo2.z) // Foo("x1", "y1", "z2")
如果更改Foo
以后:
case class Foo(w: String, x: String, y: String, z: String)
任何修改都会有许多工作要做。 明确:
val foo1 = Foo("w1", "x1", "y1", "z1")
val foo2 = Foo("w2", "x2", "y2", "z2")
val mergedFoo = foo1.copy(z = foo2.z) // Foo("w1", "x1", "y1", "z2")
文章来源: Merge two case class of same type, except some fields