【问题标题】:How to use shapeless to copy fields from one class to another different class如何使用无形将字段从一个类复制到另一个不同的类
【发布时间】:2017-03-07 23:07:55
【问题描述】:

是否可以使用 shapeless 将 1 个对象转换为另一个对象

  • 进行一些小的转换,例如将 Option[T] 转换为 T (无需为每个类手动定义映射)

  • 忽略缺失的字段

导入无形._ 导入 shapeless.syntax._

case class Cat(color: Option[Int], isFat: Boolean, newField: String)
case class Kitten(color: Int, isFat: Boolean)

val kitten = Kitten(2, true)

val genCat = Generic[Cat]
val genKit = Generic[Kitten]

val cat: Cat = genCat.from(genKit.to(kitten))

此操作失败并出现以下错误
(扩展为)shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]

【问题讨论】:

    标签: scala shapeless


    【解决方案1】:

    这是一个使用与我的previous answer 相同的想法的解决方案。

    • 进行次要转换(默认值选项)
    • 忽略尾部字段

    当然有一定的限制。

    object HListsFlatten {
    
      import shapeless.{::, HList, HNil}
    
      sealed trait DefaultValue[V] {
        def value: V
      }
    
      implicit val defaultInt: DefaultValue[Int] = new DefaultValue[Int] {
        override def value = 0
      }
    
      sealed trait HConv[From <: HList, To <: HList] {
        def convert(list: From): To
      }
    
      implicit def buildHConvNil: HConv[HNil, HNil] = new HConv[HNil, HNil] {
        override def convert(list: HNil): HNil = HNil
      }
    
      implicit def buildHConvShorten[H <: AnyVal, T <: HList]
        : HConv[::[H, T], ::[H, HNil]] = new HConv[::[H, T], ::[H, HNil]] {
        override def convert(list: ::[H, T]): ::[H, HNil] = {
          list.head :: HNil
        }
      }
    
      implicit def buildHConvOption[H, T <: HList, T2 <: HList](
          implicit conv: HConv[T, T2],
          default: DefaultValue[H]): HConv[::[Option[H], T], ::[H, T2]] =
        new HConv[::[Option[H], T], ::[H, T2]] {
          override def convert(list: ::[Option[H], T]): ::[H, T2] = {
            list.head.getOrElse(default.value) :: conv.convert(list.tail)
          }
        }
    
      implicit def buildHConv[H <: AnyVal, T <: HList, T2 <: HList](
          implicit conv: HConv[T, T2]): HConv[::[H, T], ::[H, T2]] =
        new HConv[::[H, T], ::[H, T2]] {
          override def convert(list: ::[H, T]): ::[H, T2] = {
            list.head :: conv.convert(list.tail)
          }
        }
    
      implicit def buildHConvString[T <: HList, T2 <: HList](
          implicit conv: HConv[T, T2]): HConv[::[String, T], ::[String, T2]] =
        new HConv[::[String, T], ::[String, T2]] {
          override def convert(list: ::[String, T]): ::[String, T2] = {
            list.head :: conv.convert(list.tail)
          }
        }
    
      def flatten[A <: HList, B <: HList](list: A)(implicit conv: HConv[A, B]): B =
        conv.convert(list)
    
    }
    

    例子:

    import shapeless.Generic
    
    case class Cat(color: Option[Int], isFat: Boolean, newField: String)
    case class Kitten(color: Int, isFat: Boolean)
    
    val cat = Cat(color = Some(3), isFat = true, "SomeValue")
    
    val genCat = Generic[Cat]
    val genKit = Generic[Kitten]
    
    import HListsFlatten._
    
    scala> val kitten = genKit.from(flatten(genCat.to(cat)))
    kitten: Kitten = Kitten(3,true)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-15
      • 1970-01-01
      • 1970-01-01
      • 2012-03-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多