简体   繁体   中英

shapeless case class conversion

i use shapeless for case class conversion, i have a 2 case class:

import shapeless._

case class Foo(id: Int, name: String)
case class Bar(id: Int, name: String, price: Double)

val fooGen = Generic[Foo]
val barGen = Generic[Bar]

val foo = Foo(1, "foo")
val fooRepr = fooGen.to(foo)
val additional = fooRepr :+ 1.0
val bar = barGen.from(additional)

This works fine, but when i try convert Bar to Foo

fooGen.from(barGen.to(bar))

i get an error:

found   : main.barGen.Repr
[error]     (which expands to)  shapeless.::[Int,shapeless.::    [String,shapeless.::[Double,shapeless.HNil]]]
[error]  required: main.fooGen.Repr
[error]     (which expands to)  shapeless.::[Int,shapeless.::[String,shapeless.HNil]]
[error]   println(fooGen.from(barGen.to(bar)))    

Is it possible convert one case class where more fields than in another?

Similar to how you adjust the HList representation of Foo , by adding an element, you'd have to adjust the HList representation of Bar as well, by removing the extra element:

fooGen.from(barGen.to(bar).take(2))

take takes a Nat argument, and this line of code uses the implicit conversion from an Int literal to a Nat type-level natural number.

You can find other methods available on HList s in shapeless.syntax.hlists.scala .

My answer is based on a previous answer by Travis Brown, for a somewhat similar question.

import shapeless._, ops.hlist._, ops.record._

class SameFieldConverter[T] {
    def apply[S, SR <: HList, TR <: HList, MR <: HList, IR <: HList](s: S)(implicit
      genS: LabelledGeneric.Aux[S, SR],
      genT: LabelledGeneric.Aux[T, TR],
      merger: Merger.Aux[SR, HNil, MR],
      intersection: Intersection.Aux[MR, TR, IR],
      align: Align[IR, TR]) = genT.from(intersection(merger(genS.to(s), HNil)))
  }
// defined class SameFieldConverter

def convertTo[T] = new SameFieldConverter[T]
//defined function convertTo

case class Foo(one: String, two: Int, three: Boolean)
// defined class Foo

case class Bar(three: Boolean, one: String)
// defined class Bar

convertTo[Bar](Foo("One", 2, false))
// res26: Bar = Bar(false, "One")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM