我认为这可行,但我很想听听 cmets:
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 中,那么还有一些工作要做。但可能还有其他方法可以处理。