类似于这个case class问题,但有一个小变化:
我有一个case class作为属性包含了一些深度嵌套的case classes。举个简单的例子,
case class Foo(fooPropA:Option[String], fooPropB:Option[Int])
case class Bar(barPropA:String, barPropB:Int)
case class FooBar(name:Option[String], foo:Foo, optionFoo: Option[Foo], bar:Option[Bar])
我想要将两个FooBar案例类合并在一起,取出输入中存在的值并将它们应用于一个已经存在的实例上,生成一个更新后的版本:
val fb1 = FooBar(Some("one"), Foo(Some("propA"), None), Some(Foo(Some("propA"), Some(3))), Some(Bar("propA", 4)))
val fb2 = FooBar(None, Foo(Some("updated"), Some(2)), Some(Foo(Some("baz"), None)), None)
val merged = fb1.merge(fb2)
//merged = FooBar(Some("one"), Foo(Some("updated"), Some(2)), Some(Foo(Some("baz"), Some(3))), Some(Bar("propA", 4)))
我知道可以使用镜头来组合深层嵌套的属性更新; 但是,我觉得这将需要大量的样板代码:我需要为每个属性创建一个镜头,并在父类中创建另一个组合的镜头。即使使用shapeless中更简洁的镜头创建方法,这似乎也需要很多维护工作。
棘手的部分是optionFoo
元素:在这种情况下,两个元素都存在于Some(value)
中。然而,我想合并内部可选属性,而不仅仅是用fb2
的新值覆盖fb1
。
我想知道是否有一种良好的方法将这两个值合并在一起,而只需要很少的代码。我的直觉告诉我尝试在案例类上使用unapply
方法返回元组,迭代并将元组组合成新的元组,然后将元组应用回案例类。
有没有更有效的方法来处理这个问题?
Option
的默认monoid实例的行为,第二个实例在这里被覆盖(这是您想要的Option [String]
和Option [Int]
字段)。您可以使用tags混合和匹配这些行为-如果您有兴趣,我稍后可以写一个快速示例。 - Travis Brown