假设我有两条记录。一个可能是案例类的LabelledGeneric
表示;而另一个可能是程序员提供的记录,提供人类可读的字段标签:
case class Book(author: String, title: String, quantity: Int)
val labels = ('author ->> "Author") :: ('title ->> "Title") :: ('quantity ->> "Quantity") :: HNil
有没有办法
Book
的标记通用表示和labels
的记录类型具有相同的键(或者至少label
的键是{{1}的键的子集1}})和我认为这可能是合并为每一方提取Book
见证,然后使用Keys
。 (我很乐意将这一点添加到开箱即用的无形操作中。)这使我们可以关联"元数据"到一个类的字段(例如代替使用注释)。
答案 0 :(得分:2)
我认为这有效,但我很乐意听到评论:
trait ZipByKey[L <: HList, R <: HList] extends DepFn2[L, R] {
type Out <: HList
}
object ZipByKey {
type Aux[L <: HList, R <: HList, O <: HList] = ZipByKey[L, R] { type Out = O }
implicit def hnilZip[R <: HList] = new ZipByKey[HNil, R] { type Out = HNil; override def apply(l: HNil, r: R) = HNil }
implicit def hlistZip[K, V, T <: HList, R <: HList, RV, Remainder <: HList, TO <: HList]
(implicit
remover: Remover.Aux[R, K, (RV, Remainder)],
recurse: ZipByKey.Aux[T, Remainder, TO]
) = new ZipByKey[FieldType[K, V] :: T, R] {
type Out = FieldType[K, (V, RV)] :: TO
def apply(l: FieldType[K, V] :: T, r: R): Out = {
val (rv, remainder) = remover.apply(r)
val newValue = (l.head, rv)
labelled.field[K](newValue) :: recurse.apply(l.tail, remainder)
}
}
}
使用示例:
case class Book(author: String, title: String, quantity: Int)
val labels = ('author ->> "Author") :: ('title ->> "Title") :: ('quantity ->> "Number Of") :: HNil
val generic = LabelledGeneric[Book]
def zipByKey[T, G <: HList, R <: HList, O <: HList](t: T, r: R)
(implicit generic: LabelledGeneric.Aux[T, G],
zipByKey: ZipByKey.Aux[G, R, O]): O = {
zipByKey.apply(generic.to(t), r)
}
println(zipByKey(Book("Hello", "Foo", 3), labels))
打印出来
(Foo,Id) :: (Bar,Name) :: (3,Number Of) :: HNil
如果我们想要不允许所有密钥都显示在labels
中,那么还有一些工作要做。但可能还有其他方法可以解决这个问题。