Shapeless - 将一个案例 class 变成另一个字段顺序不同的案例
Shapeless - turn a case class into another with fields in different order
我正在考虑做类似于 Safely copying fields between case classes of different types 的事情,但使用重新排序的字段,即
case class A(foo: Int, bar: Int)
case class B(bar: Int, foo: Int)
我想要一些东西将 A(3, 4)
变成 B(4, 3)
- 无形的' LabelledGeneric
想到了,但是
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)))
^
如何对记录中的字段重新排序 (?) 以便使用最少的样板文件?
注意到@MilesSabin(神一样的无形创造者),有一个对齐操作,它的用法如下:
import ops.hlist.Align
val aGen = LabelledGeneric[A]
val bGen = LabelledGeneric[B]
val align = Align[aGen.Repr, bGen.Repr]
bGen.from(align(aGen.to(A(12, 13)))) //> res0: B = B(13,12)
P.S。注意到有一个 example on GitHub.
我应该把这个留给迈尔斯,但这是我来自的地方的欢乐时光,我无法抗拒。正如他在上面的评论中指出的那样,关键是 ops.hlist.Align
,这对记录(毕竟只是特殊的 hlist)来说效果很好。
如果你想要一个好的语法,你需要使用像下面这样的技巧来将类型参数列表与目标(你想明确提供)与类型参数列表与所有其他东西(它你想被推断):
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)
请注意,对于大型案例 类。
,在编译时查找对齐实例会变得很昂贵
我正在考虑做类似于 Safely copying fields between case classes of different types 的事情,但使用重新排序的字段,即
case class A(foo: Int, bar: Int)
case class B(bar: Int, foo: Int)
我想要一些东西将 A(3, 4)
变成 B(4, 3)
- 无形的' LabelledGeneric
想到了,但是
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)))
^
如何对记录中的字段重新排序 (?) 以便使用最少的样板文件?
注意到@MilesSabin(神一样的无形创造者),有一个对齐操作,它的用法如下:
import ops.hlist.Align
val aGen = LabelledGeneric[A]
val bGen = LabelledGeneric[B]
val align = Align[aGen.Repr, bGen.Repr]
bGen.from(align(aGen.to(A(12, 13)))) //> res0: B = B(13,12)
P.S。注意到有一个 example on GitHub.
我应该把这个留给迈尔斯,但这是我来自的地方的欢乐时光,我无法抗拒。正如他在上面的评论中指出的那样,关键是 ops.hlist.Align
,这对记录(毕竟只是特殊的 hlist)来说效果很好。
如果你想要一个好的语法,你需要使用像下面这样的技巧来将类型参数列表与目标(你想明确提供)与类型参数列表与所有其他东西(它你想被推断):
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)
请注意,对于大型案例 类。
,在编译时查找对齐实例会变得很昂贵