2015-11-04 49 views
0

在我的项目中,有很多地方将对象从集合中挑出,复制一些值更改并推回到集合中。我一直在尝试创建自己的“复制”方法,除了制作副本之外,还给了我一个“差异”对象。换句话说,就是包含你刚才放入它的论点的东西。Scala复制和反射

然后应该将'差异'对象发送到某个地方进行聚合,以便其他人可以获取自上次以来所有更改的报告,而不发送实际的整个对象。这一切很简单,如果一个做这样的:

val user = new User(Some(23), true, "arne", None, None, "position", List(), "email", None, false) 
val user0 = user.copy(position = "position2") 
list ::= user0 
val diff = new Diff[User](Map("position" -> "position2")) 

然而,有一些重复的工作,在那里,我就非常喜欢,只是有它的一个方法,如:

val (user, diff) = user.copyAndDiff(position = "position") 

我一直无法弄清楚“复制”的参数实际需要什么形式,但我也可以使用其他形式。

我做了一个带有Type参数的方法,它应该创建一个副本和一个diff。事情是这样的:

object DiffCopy[Copyable]{ 
    def apply(original:Copyable, changes:Map[String, Any]){ 
    original.copy(??uhm.. 
    original.getAllTheFieldsAndCopyAndOverWriteSomeAccordingToChanges?? 

我的第一个问题是,似乎没有被任何方式保证其原有的对象有一个“复制”的方法,我可以超载。当我想要将更改实际分配给新的复制对象中正确的字段时,会出现第二个问题。我试图用Reflection来调试,并试图找到一种方法来设置字段值的字段值。在这种情况下,我可以将我的差异保存为简单的地图,并且只需首先创建此差异地图,然后将其应用于我的对象,并将它们发送到他们需要去的地方。

但是,我在兔子洞里越来越深,越来越远离我真正想要的东西。我得到了一个点,我有一个任意对象的字段数组,并可以通过名称获得它们,但我无法让它适用于泛型类型。所以现在我在这里问,如果有人能就这种情况给我一些建议吗?

我可以得到的最好的答案是,如果有人能告诉我一个简单的方法来将一个Map [String,Any]应用到相当于'copy'方法的东西。我相当肯定这应该是可能实现的,但它目前仅限于我...

+1

这是不完全清楚,我你想完成什么。更新一个不可变集合中的不可变对象?然后你应该看一下镜头库,例如[单片眼镜](https://github.com/julien-truffaut/Monocle)。可以肯定的是,反思并不是用scala解决这个问题的惯用方法, –

+0

这个集合并不是真正的问题的一部分。集合可变,对象不可变。我想替换该对象并创建另一个代表所做更改的对象。 – Osthekake

回答

1

有点过于复杂但解决了您的原始问题。

我可以得到的最好的答案是,如果有人能告诉我一个简单的方法来将一个Map [String,Any]应用到相当于'copy'方法的东西。我相当肯定这应该是可以实现的,但它只是目前超越我...

  1. 采取从案例类中的所有字段映射。

  2. 用新值更新地图。

  3. 从新字段映射创建案例类。

问题:

  • 低性能

我敢肯定,这是可以做到更简单...

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

    def getCCParams(cc: Any) = 
    (Map[String, Any]() /: cc.getClass.getDeclaredFields) {(a, f) => 
     f.setAccessible(true) 
     a + (f.getName -> f.get(cc)) 
    } 

    def enrichCaseClass[T](cc: T, vals : Map[String, Any])(implicit cmf : ClassManifest[T]) = { 
    val ctor = cmf.erasure.getConstructors().head 
    val params = getCCParams(cc.asInstanceOf[Any]) ++ vals 
    val args = cmf.erasure.getDeclaredFields().map(f => params(f.getName).asInstanceOf[Object]) 
    ctor.newInstance(args : _*).asInstanceOf[T] 
    } 

    val j = Person("Jack", 15) 
    enrichCaseClass(j, Map("age" -> 18)) 
+0

这很好。但是你说得对,它表现不佳。我想我会坚持只记得在每次更新对象时手动进行复制和手动比较。 – Osthekake