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