2017-03-07 35 views
4

是否有可能使用無形轉換1對象到另一個對象,而如何使用不成形從一個類複製場到另一個不同的類

  • 做一些細微的變換就像轉換選項[T]到T (無手動定義映射用於每個類別)

  • 忽略丟失的字段

進口shapeless._ 進口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]

回答

0

這是一個使用與我的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) 
相關問題