scala – 自动将案例类转换为无形的可扩展记录?
如果我有这两个案例类:
case class Address(street : String,zip : Int) case class Person(name : String,address : Address) 和一个实例: val person = Person("Jane",Address("street address",12345)) 有没有办法在无形状中自动将人转换为可扩展记录? 我对浅层和深层转换感兴趣. 浅拷贝将是这样的: 'name ->> "Jane" :: 'address ->> Address("street address",12345) :: HNil 在深度转换中,嵌套的case类也成为记录: 'name ->> "Jane" :: 'address ->> ('street ->> "street address" :: 'zip ->> 12345 :: HNil) :: HNil 我也有兴趣将记录转换回案例类. 解决方法
假设我们有以下设置:
import shapeless._,shapeless.labelled.{ FieldType,field } case class Address(street: String,zip: Int) case class Person(name: String,address: Address) val person = Person("Jane",12345)) type ShallowPersonRec = FieldType[Witness.`'name`.T,String] :: FieldType[Witness.`'address`.T,Address] :: HNil type DeepPersonRec = FieldType[Witness.`'name`.T,String] :: FieldType[ Witness.`'address`.T,FieldType[Witness.`'street`.T,String] :: FieldType[Witness.`'zip`.T,Int] :: HNil ] :: HNil Shapeless的LabelledGeneric直接支持浅层案例: val shallow: ShallowPersonRec = LabelledGeneric[Person].to(person) 或者,如果您想要一个通用的帮助方法: def shallowRec[A](a: A)(implicit gen: LabelledGeneric[A]): gen.Repr = gen.to(a) val shallow: ShallowPersonRec = shallowRec(person) 您可以从以下位置返回: scala> val originalPerson = LabelledGeneric[Person].from(shallow) originalPerson: Person = Person(Jane,Address(street address,12345)) 深层的情况比较棘手,据我所知,没有方便的方法可以使用Shapeless提供的类型类和其他工具,但你可以调整我的代码来自this question(现在是无形的test case)来做什么你要.首先是类型类本身: trait DeepRec[L] extends DepFn1[L] { type Out <: HList def fromRec(out: Out): L } 然后是记录头部本身没有LabelledGeneric实例的低优先级实例: trait LowPriorityDeepRec { type Aux[L,Out0] = DeepRec[L] { type Out = Out0 } implicit def hconsDeepRec0[H,T <: HList](implicit tdr: Lazy[DeepRec[T]] ): Aux[H :: T,H :: tdr.value.Out] = new DeepRec[H :: T] { type Out = H :: tdr.value.Out def apply(in: H :: T): H :: tdr.value.Out = in.head :: tdr.value(in.tail) def fromRec(out: H :: tdr.value.Out): H :: T = out.head :: tdr.value.fromRec(out.tail) } } 然后是伴侣对象的其余部分: object DeepRec extends LowPriorityDeepRec { def toRec[A,Repr <: HList](a: A)(implicit gen: LabelledGeneric.Aux[A,Repr],rdr: DeepRec[Repr] ): rdr.Out = rdr(gen.to(a)) class ToCcPartiallyApplied[A,Repr](val gen: LabelledGeneric.Aux[A,Repr]) { type Repr = gen.Repr def from[Out0,Out1](out: Out0)(implicit rdr: Aux[Repr,Out1],eqv: Out0 =:= Out1 ): A = gen.from(rdr.fromRec(eqv(out))) } def to[A](implicit gen: LabelledGeneric[A] ): ToCcPartiallyApplied[A,gen.Repr] = new ToCcPartiallyApplied[A,gen.Repr](gen) implicit val hnilDeepRec: Aux[HNil,HNil] = new DeepRec[HNil] { type Out = HNil def apply(in: HNil): HNil = in def fromRec(out: HNil): HNil = out } implicit def hconsDeepRec1[K <: Symbol,V,Repr <: HList,T <: HList](implicit gen: LabelledGeneric.Aux[V,hdr: Lazy[DeepRec[Repr]],tdr: Lazy[DeepRec[T]] ): Aux[FieldType[K,V] :: T,FieldType[K,hdr.value.Out] :: tdr.value.Out] = new DeepRec[FieldType[K,V] :: T] { type Out = FieldType[K,hdr.value.Out] :: tdr.value.Out def apply( in: FieldType[K,V] :: T ): FieldType[K,hdr.value.Out] :: tdr.value.Out = field[K](hdr.value(gen.to(in.head))) :: tdr.value(in.tail) def fromRec( out: FieldType[K,hdr.value.Out] :: tdr.value.Out ): FieldType[K,V] :: T = field[K](gen.from(hdr.value.fromRec(out.head))) :: tdr.value.fromRec(out.tail) } } (请注意,必须将DeepRec特征和对象一起定义为伴随.) 这很麻烦,但它有效: scala> val deep: DeepPersonRec = DeepRec.toRec(person) deep: DeepPersonRec = Jane :: (street address :: 12345 :: HNil) :: HNil scala> val originalPerson = DeepRec.to[Person].from(deep) originalPerson: Person = Person(Jane,12345)) 转换回case类的to / from语法是必要的,因为任何给定的记录都可以对应很多潜在的case类,所以我们需要能够指定目标类型,因为Scala不支持部分应用的类型参数列表,我们必须将操作分解为两部分(其中一部分将明确指定其类型,而另一部分的类型参数将被推断). (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 爱吃螃蟹的前端:登上 Bootstrap 4.0 的大船
- 《数据结构》实验一: VC编程工具的灵活使用
- 使用Scala期货时如何捕获RejectedExecutionException?
- Scala Macro:使用Option类型创建新类
- 连webservice时SoapObject对象找不到
- XFire实现WebService一:使用XfireConfigurableServlet
- angularjs – 如何获取角度“|的结果数组过滤“表达式在变量
- webservice之cxf相关问题
- bootstrap-table 插件的使用
- Basic Tutorials of Redis(5) - Sorted Set