合并两个案例类中的非空字段

时间:2016-07-21 15:14:28

标签: scala shapeless

我试图将caseclassmerge示例从无形库修改为仅合并非空字段。

object mergeSyntax {
  implicit class MergeSyntax[T](t: T) {
    def merge[U](u: U)(implicit merge: CaseClassMerge[T, U]): T = merge(t, u)
  }
}

trait CaseClassMerge[T, U] {
  def apply(t: T, u: U): T
}

object CaseClassMerge {
  import ops.record.Merger

  def apply[T, U](implicit merge: CaseClassMerge[T, U]): CaseClassMerge[T, U] = merge

  implicit def mkCCMerge[T, U, RT <: HList, RU <: HList]
    (implicit
      tgen: LabelledGeneric.Aux[T, RT],
      ugen: LabelledGeneric.Aux[U, RU],
      merger: Merger.Aux[RT, RU, RT]
    ): CaseClassMerge[T, U] =
    new CaseClassMerge[T, U] {
      def apply(t: T, u: U): T =
        tgen.from(merger(tgen.to(t), ugen.to(u)))
    }
}

如何修改合并逻辑,使第二个参数中的非空字段合并到第一个参数中?

1 个答案:

答案 0 :(得分:1)

您可以将自己的隐式合并实现添加到当前作用域,覆盖标准合并:

object NotNullHListMerger {
  import shapeless.labelled._
  import shapeless.ops.record.Merger
  import shapeless.ops.record.Remover

  implicit def notNullHListMerger[K, V, T <: HList, M <: HList, MT <: HList]
  (implicit
   rm: Remover.Aux[M, K, (V, MT)],
   mt: Merger[T, MT]
  ): Merger.Aux[FieldType[K, V] :: T, M, FieldType[K, V] :: mt.Out] =
    new Merger[FieldType[K, V] :: T, M] {
      type Out = FieldType[K, V] :: mt.Out
      def apply(l: FieldType[K, V] :: T, m: M): Out = {
        val (mv, mr) = rm(m)
        val up = field[K](mv)
        // Replace only if value is not null
        val h = Option(up).getOrElse(l.head)
        h :: mt(l.tail, mr)
      }
    }
}

import mergeSyntax._
import NotNullHListMerger._

case class Foo(i: Int, s: String, b: Boolean)
case class Bar(b: Boolean, s: String)

val foo = Foo(23, "foo", true)
val bar = Bar(false, null)

val merged = foo merge bar
assert(merged == Foo(23, "foo", false))