【发布时间】:2016-08-25 01:16:37
【问题描述】:
我正在编写一个泛型类型类(DynamoDB 的编解码器),使用 Shapeless 派生代码。我有一个不使用案例类的字段名称的版本,纯粹基于类字段的顺序与 DynamoDB 响应中的属性顺序相匹配的想法。它使用Generic 和通常的deriveHNil、deriveHCons 方法,例如在此处描述:https://meta.plasm.us/posts/2015/11/08/type-classes-and-generic-derivation/。
现在我想要一个使用字段名称来查找相关 DynamoDB 属性的版本。我目前的想法是主要重用以前(基于订单)版本的方法,另外让编译器通过LabelledGeneric 和shapeless.ops.record.Keys 提供字段名称。但是,我坚持如何正确使用 Keys 功能。
想法如下:函数hconsDecoder应该一次做两件事:解构HList以在其头+尾上运行decode操作,并从上述头中提取标签。 LabelledGeneric 应该为HList 提供字段上的标签,以便hconsDecoder 中的H 类型参数将成为记录中的一个条目,包含相关信息。但是因为Keys 只能在HList 上工作,所以我创建了一个单例H :: HNil 来运行Keys。
这是我拥有的部分代码:
trait FieldDecoder[A] {
def decode(a: AttributeValue): Option[A]
}
trait RecordDecoder[A] {
def decode(s: Seq[Attribute]): Option[A]
}
object RecordDecoderInstances {
implicit val hnilDecoder = new RecordDecoder[HNil] {
override def decode(s: Seq[Attribute]): Option[HNil] = {
Some(HNil)
}
}
object toName extends Poly1 {
implicit def keyToName[A] = at[Symbol with A](_.name)
}
implicit def hconsDecoder[H: FieldDecoder, T <: HList: RecordDecoder](
implicit kk: Keys[H :: HNil]#Out,
m: Mapper[toName.type, Keys[H :: HNil]#Out]) =
new RecordDecoder[H :: T] {
override def decode(s: Seq[Attribute]): Option[H :: T] = {
val attrName = (kk map toName).head.asInstanceOf[String] // compile error here
for {
h <- implicitly[FieldDecoder[H]]
.decode(s.filter(_.name == attrName).head.value)
t <- implicitly[RecordDecoder[T]]
.decode(s.filterNot(_.name == attrName))
} yield h :: t
}
}
}
鉴于此代码,编译器错误如下:could not find implicit value for parameter c: shapeless.ops.hlist.IsHCons[m.Out]。我尝试过相同的不同版本,总是面临implicit not found 错误的一些变化。底线是,Keys 由于某种原因不适用于 H :: HNil 构造。
这是我第一次认真尝试 Shapeless,我不知道我是否走对了路。对于这个特定错误和我的总体方法,我将不胜感激。
【问题讨论】: