为递归数据结构定义`Codec`

时间:2015-09-25 21:32:07

标签: scala shapeless scodec

我有一个类似的课程,

case class Foo ( bar: Int, foos: Vector[Foo] )

定义Codec[Foo],我试过了,

def fc = shapeless.Lazy((int32 ~~ vector(fc)).widenOpt( (Foo.apply _).tupled, Foo.unapply _ ))

但这不起作用,因为scodec会抛出StackOverflowError。这样做的正确方法是什么?

1 个答案:

答案 0 :(得分:3)

您需要scodec.codecs.lazily组合器来构建递归编解码器(而不是shapeless.lazily)。例如:

scala> def fc: Codec[Foo] = lazily((int32 :: vector(fc)).as[Foo])
fc: scodec.Codec[Foo]

scala> val res = fc.encode(Foo(1, Vector(Foo(2, Vector.empty)))).require
res: scodec.bits.BitVector = BitVector(64 bits, 0x0000000100000002)

scala> fc.decode(res)
res2: scodec.Attempt[scodec.DecodeResult[Foo]] = Successful(DecodeResult(Foo(1,Vector(Foo(2,Vector()))),BitVector(empty)))

在scodec 1.8.2及之前的版本中,派生此编解码器而不是显式定义它会导致编译时出错,因为派生会永远递归递归。从1.8.3开始,可以自动导出此编解码器。

有关递归树的示例,请参阅this example from scodec source