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

前端 未结 2 1385
悲哀的现实
悲哀的现实 2020-12-07 21:00

I\'m thinking of doing something similar to Safely copying fields between case classes of different types but with reordered fields, i.e.

case class A(foo: I         


        
相关标签:
2条回答
  • 2020-12-07 21:44

    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.

    0 讨论(0)
  • 2020-12-07 21:51

    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.

    0 讨论(0)
提交回复
热议问题