作为SCodec的新用户,有一个相当的学习曲线。尽管阅读了源代码和文档,我还是遇到了一些似乎无法解决的问题。
我希望能够将流行的编解码器定义为像这样的函数
def packedByte : Codec[Int :: Int :: Int :: HNil] = uint(4) :: uint(2) :: uint(2)
然后将它们组合到更高级别的编解码器中,这些编解码器对像
这样的案例类进行解码和编码case class MyPacket(foo : Boolean, first : Int, second : Int, third : Int, bar : Boolean)
def packet : Codec[MyPacket] = (bool :: packedByte :: bool).as[MyPacket]
但是,这不起作用
无法证明自己是无形的。:[布尔,无形。:无形。:我的,无形。:我是无形的。:无瑕疵。形状,无形。: :[Boolean,shapeless.HNil]]]可以转换为cmd504.MyPacket。
然而,当我“内联”packedByte
时,就像
def packetInline : Codec[MyPacket] = (bool :: uint(4) :: uint(2) :: uint(2) :: bool).as[MyPacket]
所有内容都按预期编译和工作。我的直觉告诉我,编解码器必须“扁平化”(基于错误消息中的两个HNils),但我无法压缩编解码器本身或内部HList表示。
答案 0 :(得分:4)
通过考虑在类似情况下如何使用普通值级别列表来开始推理hlists通常很有用。例如,假设我们有一个值和一个列表:
val x = 0
val xs = List(1, 2, 3)
我们希望在x
之前和之后创建一个xs
的新列表。我们可以使用+:
和:+
:
scala> x +: xs :+ x
res0: List[Int] = List(0, 1, 2, 3, 0)
或者:
scala> x :: (xs :+ x)
res1: List[Int] = List(0, 1, 2, 3, 0)
对于Scodec,没有+:
运算符,但有::
和:+
,您可以完全按照在值级别使用列表版本的方式使用它们:
import scodec._, scodec.codecs._, shapeless._
def packedByte: Codec[Int :: Int :: Int :: HNil] =
uint(4) :: uint(2) :: uint(2)
case class MyPacket(
foo: Boolean,
first: Int,
second: Int,
third: Int,
bar: Boolean
)
def packet: Codec[MyPacket] = (bool :: (packedByte :+ bool)).as[MyPacket]
有可能构建一个嵌套的hlist,然后将其展平,但:+
更加惯用。