Shapeless LabelledGeneric 但忽略了一些字段
Shapeless LabelledGeneric but ignoring some fields
我想定义一个无形的 LabelledGeneric
,它在转换为 HList
时忽略一个(或多个)字段;当再次将 HList
转换回来时,它应该替换为用户定义的值。目标是能够写出这样的东西:
case class Foo(i: Int, s: String)
val foo = Foo(123, "Hello")
val gen = LabelledGeneric[Foo].ignoring('i)(defaultValue = -1)
val hlist = gen.to(foo)
// "Hello" :: HNil
val foo2 = gen.from(hlist)
assert(foo2 == Foo(-1, "Hello"))
这就是我目前所拥有的。它可以编译,但是当我尝试使用它时,我无法让类型正确排列以进行隐式解析:
implicit class IgnoringOps[T](orig: LabelledGeneric[T]) {
def ignoring[Orig <: HList, V, Ign <: HList](k: Witness)(defaultValue: V)(implicit
gen: LabelledGeneric.Aux[T, Orig],
rem: Remover.Aux[Orig, FieldType[k.T, V], Ign],
upd: Updater.Aux[Ign, FieldType[k.T, V], Orig]): LabelledGeneric[T] = {
new LabelledGeneric[T] {
override type Repr = Ign
override def to(t: T): Ign = rem(gen.to(t))
override def from(r: Ign): T = gen.from(upd(r, field[k.T](defaultValue)))
}
}
}
任何人都可以阐明我做错了什么吗?
这应该按预期工作(根据您的示例):
implicit class IgnoringOps[T, L <: HList](gen: LabelledGeneric.Aux[T, L]) {
def ignoring[V, I <: HList, H <: HList](k: Witness)(v: V)(implicit
rem: Remover.Aux[L, k.T, (V, I)],
upd: Updater.Aux[I, FieldType[k.T, V], H],
ali: Align[H, L]
): LabelledGeneric[T] = new LabelledGeneric[T] {
override type Repr = I
//`rem` is implicitly used there
override def to(t: T): I = gen.to(t) - k
//`upd` and `ali` are implicitly used there
override def from(r: I): T = gen.from(r + field[k.T](v))
}
}
备注:
- 从
ignoring
中删除了隐式参数 gen: LabelledGeneric.Aux[T, L]
,您可以利用隐式 class 参数 orig
;
- 使用了
RecordOps
中的 -
和 +
方法,而不是显式使用 rem
和 upd
;
- 已将
rem
implicit parameter 从 Remover.Aux[L, FieldType[k.T, V], I],
更新为 Remover.Aux[L, k.T, (V, I)]
;
- 添加了中间助手
H <: HList
;
- 更新了
upd
隐式参数,使用上述中间助手,从 Updater.Aux[I, FieldType[k.T, V], L]
到 Updater.Aux[I, FieldType[k.T, V], H]
;
- 添加
ali
隐式要求对齐 H
和 L
:ali: Align[H, L]
我想定义一个无形的 LabelledGeneric
,它在转换为 HList
时忽略一个(或多个)字段;当再次将 HList
转换回来时,它应该替换为用户定义的值。目标是能够写出这样的东西:
case class Foo(i: Int, s: String)
val foo = Foo(123, "Hello")
val gen = LabelledGeneric[Foo].ignoring('i)(defaultValue = -1)
val hlist = gen.to(foo)
// "Hello" :: HNil
val foo2 = gen.from(hlist)
assert(foo2 == Foo(-1, "Hello"))
这就是我目前所拥有的。它可以编译,但是当我尝试使用它时,我无法让类型正确排列以进行隐式解析:
implicit class IgnoringOps[T](orig: LabelledGeneric[T]) {
def ignoring[Orig <: HList, V, Ign <: HList](k: Witness)(defaultValue: V)(implicit
gen: LabelledGeneric.Aux[T, Orig],
rem: Remover.Aux[Orig, FieldType[k.T, V], Ign],
upd: Updater.Aux[Ign, FieldType[k.T, V], Orig]): LabelledGeneric[T] = {
new LabelledGeneric[T] {
override type Repr = Ign
override def to(t: T): Ign = rem(gen.to(t))
override def from(r: Ign): T = gen.from(upd(r, field[k.T](defaultValue)))
}
}
}
任何人都可以阐明我做错了什么吗?
这应该按预期工作(根据您的示例):
implicit class IgnoringOps[T, L <: HList](gen: LabelledGeneric.Aux[T, L]) {
def ignoring[V, I <: HList, H <: HList](k: Witness)(v: V)(implicit
rem: Remover.Aux[L, k.T, (V, I)],
upd: Updater.Aux[I, FieldType[k.T, V], H],
ali: Align[H, L]
): LabelledGeneric[T] = new LabelledGeneric[T] {
override type Repr = I
//`rem` is implicitly used there
override def to(t: T): I = gen.to(t) - k
//`upd` and `ali` are implicitly used there
override def from(r: I): T = gen.from(r + field[k.T](v))
}
}
备注:
- 从
ignoring
中删除了隐式参数gen: LabelledGeneric.Aux[T, L]
,您可以利用隐式 class 参数orig
; - 使用了
RecordOps
中的-
和+
方法,而不是显式使用rem
和upd
; - 已将
rem
implicit parameter 从Remover.Aux[L, FieldType[k.T, V], I],
更新为Remover.Aux[L, k.T, (V, I)]
; - 添加了中间助手
H <: HList
; - 更新了
upd
隐式参数,使用上述中间助手,从Updater.Aux[I, FieldType[k.T, V], L]
到Updater.Aux[I, FieldType[k.T, V], H]
; - 添加
ali
隐式要求对齐H
和L
:ali: Align[H, L]