Shapeless - 将一个 case 类变成另一个具有不同顺序的字段 [英] Shapeless - turn a case class into another with fields in different order

查看:40
本文介绍了Shapeless - 将一个 case 类变成另一个具有不同顺序的字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在考虑做一些类似于 安全复制的事情不同类型的案例类之间的字段,但具有重新排序的字段,即

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: Int, bar: Int)
case class B(bar: Int, foo: Int)

我想要一些东西将 A(3, 4) 变成 B(4, 3) - 无形状的 LabelledGeneric 浮现在脑海中,然而

And I'd like to have something to turn a A(3, 4) into a B(4, 3) - shapeless' LabelledGeneric comes to mind, however

LabelledGeneric[B].from(LabelledGeneric[A].to(A(12, 13)))

结果

<console>:15: error: type mismatch;
 found   : shapeless.::[shapeless.record.FieldType[shapeless.tag.@@[Symbol,String("foo")],Int],shapeless.::[shapeless.record.FieldType[shapeless.tag.@@[Symbol,String("bar")],Int],shapeless.HNil]]
    (which expands to)  shapeless.::[Int with shapeless.record.KeyTag[Symbol with shapeless.tag.Tagged[String("foo")],Int],shapeless.::[Int with shapeless.record.KeyTag[Symbol with shapeless.tag.Tagged[String("bar")],Int],shapeless.HNil]]
 required: shapeless.::[shapeless.record.FieldType[shapeless.tag.@@[Symbol,String("bar")],Int],shapeless.::[shapeless.record.FieldType[shapeless.tag.@@[Symbol,String("foo")],Int],shapeless.HNil]]
    (which expands to)  shapeless.::[Int with shapeless.record.KeyTag[Symbol with shapeless.tag.Tagged[String("bar")],Int],shapeless.::[Int with shapeless.record.KeyTag[Symbol with shapeless.tag.Tagged[String("foo")],Int],shapeless.HNil]]
              LabelledGeneric[B].from(LabelledGeneric[A].to(A(12, 13)))
                                                           ^

如何对记录中的字段重新排序 (?) 以便使用最少的样板文件?

How do I reorder the fields in the record (?) so this can work with a minimum of boilerplate?

推荐答案

我应该把这个留给 Miles 但这是我来自的欢乐时光,我无法抗拒.正如他在上面的评论中指出的那样,关键是 ops.hlist.Align,它适用于记录(毕竟只是特殊的 hlist).

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]

然后:

case class A(foo: Int, bar: Int)
case class B(bar: Int, foo: Int)

然后:

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.

这篇关于Shapeless - 将一个 case 类变成另一个具有不同顺序的字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆