Shapeless - turn a case class into another with fields in different order

早过忘川 提交于 2019-11-28 17:05:00

I should leave this for Miles but it's happy hour where I'm from and I can't resist. As he points out in a comment above, the key is ops.hlist.Align, which will work just fine for records (which are just special hlists, after all).

If you want a nice syntax, you need to use a trick like the following for separating the type parameter list with the target (which you want to provide explicitly) from the type parameter list with all the other stuff (which you want to be inferred):

import shapeless._, ops.hlist.Align

class SameFieldsConverter[T] {
  def apply[S, SR <: HList, TR <: HList](s: S)(implicit
    genS: LabelledGeneric.Aux[S, SR],
    genT: LabelledGeneric.Aux[T, TR],
    align: Align[SR, TR]
  ) = genT.from(align(genS.to(s)))
}

def convertTo[T] = new SameFieldsConverter[T]

And then:

case class A(foo: Int, bar: Int)
case class B(bar: Int, foo: Int)

And then:

scala> convertTo[B](A(12, 13))
res0: B = B(13,12)

Note that finding alignment instances will get expensive at compile time for large case classes.

DaunnC

As noticed @MilesSabin (godlike shapeless creator), there is an align operation, it is used like:

import ops.hlist.Align

val aGen = LabelledGeneric[A]
val bGen = LabelledGeneric[B]
val align = Align[aGen.Repr, bGen.Repr]
bGen.from(align(aGen.to(A(12, 13)))) //> res0: B = B(13,12)

P.S. Noticed that there is an example on GitHub.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!