首页 > 解决方案 > 如何对齐无形记录?

问题描述

给定

case class Foo(a: Int, c: Int)
case class Bar(a: Int, b: Int, c: Int)

我想写一个看起来像这样的函数:

def mkBar(foo: Foo, b: Int): Bar = {
  import shapeless.syntax.singleton._

  val fooRecords = LabelledGeneric[Foo].to(foo)
  val bRecord = 'b ->> b
  val allRecords = fooRecords :+ bRecord

  // Doesn't work as it's a c b and we need a b c
  LabelledGeneric[Bar].from(allRecords)
}

即给定一个Foo 和ab,创建一个Bar。此代码无法编译,因为我附加了“b”而不是将其插入 Hlist 的中间。

我知道我可以使用 anhlist.Align与 a 对齐,Bar但我看到的所有示例都显示了两个 Reprs 例如Align[FooGen.Repr, BarGen.Repr]。在我的情况下,我没有allRecords实例的Repr,所以我不知道如何派生合适的 Align 实例。

如何将“动态”Hlist 与Repr 对齐?

标签: scalashapeless

解决方案


因此解决方案是将代码拆分为另一个带有类型参数和隐式 Align 实例的函数。最后我想出了这个:

object ShapelessOps {

  import shapeless._
  import shapeless.ops.hlist

  trait Converter[A, B] {
    def apply(a: A): B
  }

  implicit class ConverterOps[A](a: A) {
    def as[B](implicit converter: Converter[A, B]): B = converter.apply(a)
  }

  implicit def genericConverter[B, BRepr <: HList, Unaligned <: HList](
    implicit
    bGen    : LabelledGeneric.Aux[B, BRepr],
    align   : hlist.Align[Unaligned, BRepr]
  ): Converter[Unaligned, B] = new Converter[Unaligned, B] {
    def apply(a: Unaligned): B = bGen.from(align.apply(a))
  }

}

我像这样使用它:

val fooRecords = LabelledGeneric[Foo].to(foo)
val bRecord = 'b ->> b
val allRecords = fooRecords :+ bRecord
allRecords.as[Bar]

推荐阅读