2015-09-25 85 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

感謝您的建議。我嘗試過,但仍然以國有企業而告終。事實上,即使我給沒有引起編譯錯誤的原始定義,只有當我試圖在運行時將其打印在控制檯中,過程與國有企業 – Sheng

+0

崩潰將是巨大的,如果scodec能夠提供某種形式的例子說明如何爲樹形數據結構創建一個編解碼器。我認爲我的問題歸結爲這一點。 – Sheng

+0

但這會在運行時拋出SOE。 def fc:Codec [Foo] = {import shapeless._; lazily((int32 :: vector(fc))。as [Foo])}有什麼區別? – Sheng