2015-09-25 2 views
2

У меня есть класс, похожий на это,определить `Codec` рекурсивной структуры данных

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. Каков правильный способ сделать это?

ответ

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.

+0

спасибо за предложение. Я попробовал, но все же закончил с SOE. На самом деле даже исходное определение, которое я дал, не вызывало ошибки компиляции, только когда я попытался распечатать его в консоли во время выполнения, процесс, разбитый с помощью SOE – Sheng

+0

, был бы замечательным, если Scodec может предоставить какой-то пример, описывающий, как создайте Codec для дерева как структуру данных. Я думаю, что моя проблема сводится к этому. – Sheng

+0

, но это вызывает SOE во время выполнения. def fc: Codec [Foo] = {import shapeless._; lazily ((int32 :: vector (fc)). как [Foo])} В чем разница? – Sheng

Смежные вопросы