2013-10-07 11 views
5

scala-picklingの現在の制限を回避するためにカスタムSPickler/Unpicklerのペアを作成しようとしています。 私がピケをしようとしているデータ型は、フィールドのいくつかがすでに独自のSPicklerとUnpicklerインスタンスを持っているケースクラスです。 私のカスタムピックラーでこれらのインスタンスを使用したいと思いますが、私はどのようにわかりません。私は実際に作業例をいただければ幸いですScala Pickling:ネストされた構造のカスタムpickler/unpicklerの作成

// Here's a class for which I want a custom SPickler/Unpickler. 
// One of its fields can already be pickled, so I'd like to reuse that logic. 
case class MyClass[A: SPickler: Unpickler: FastTypeTag](myString: String, a: A) 

// Here's my custom pickler. 
class MyClassPickler[A: SPickler: Unpickler: FastTypeTag](
    implicit val format: PickleFormat) extends SPickler[MyClass[A]] with Unpickler[MyClass[A]] { 
    override def pickle(
    picklee: MyClass[A], 
    builder: PBuilder) { 
    builder.beginEntry(picklee) 

    // Here we save `myString` in some custom way. 
    builder.putField(
     "mySpecialPickler", 
     b => b.hintTag(FastTypeTag.ScalaString).beginEntry(
     picklee.myString).endEntry()) 

    // Now we need to save `a`, which has an implicit SPickler. 
    // But how do we use it? 

    builder.endEntry() 
    } 

    override def unpickle(
    tag: => FastTypeTag[_], 
    reader: PReader): MyClass[A] = { 
    reader.beginEntry() 

    // First we read the string. 
    val myString = reader.readField("mySpecialPickler").unpickle[String] 

    // Now we need to read `a`, which has an implicit Unpickler. 
    // But how do we use it? 
    val a: A = ??? 

    reader.endEntry() 

    MyClass(myString, a) 
    } 
} 

は、ここで私が何を意味するかの例です。 ありがとう! MyClassの型パラメータは、コンテキスト境界を必要としないことを

case class MyClass[A](myString: String, a: A) 

注:ここでは

答えて

5

は実施例です。唯一のカスタムPicklerさんのクラスは、対応する暗黙の必要があります:カスタムPicklerさんのクラスに加えて

class MyClassPickler[A](implicit val format: PickleFormat, aTypeTag: FastTypeTag[A], 
            aPickler: SPickler[A], aUnpickler: Unpickler[A]) 
    extends SPickler[MyClass[A]] with Unpickler[MyClass[A]] { 

    private val stringUnpickler = implicitly[Unpickler[String]] 

    override def pickle(picklee: MyClass[A], builder: PBuilder) = { 
    builder.beginEntry(picklee) 

    builder.putField("myString", 
     b => b.hintTag(FastTypeTag.ScalaString).beginEntry(picklee.myString).endEntry() 
    ) 

    builder.putField("a", 
     b => {  
     b.hintTag(aTypeTag) 
     aPickler.pickle(picklee.a, b) 
     } 
    ) 

    builder.endEntry() 
    } 

    override def unpickle(tag: => FastTypeTag[_], reader: PReader): MyClass[A] = { 
    reader.hintTag(FastTypeTag.ScalaString) 
    val tag = reader.beginEntry() 
    val myStringUnpickled = stringUnpickler.unpickle(tag, reader).asInstanceOf[String] 
    reader.endEntry() 

    reader.hintTag(aTypeTag) 
    val aTag = reader.beginEntry() 
    val aUnpickled = aUnpickler.unpickle(aTag, reader).asInstanceOf[A] 
    reader.endEntry() 

    MyClass(myStringUnpickled, aUnpickled) 
    } 

} 

を、我々はまた、具体的な型引数に特化Picklerさんのインスタンスを返します暗黙のDEFが必要になります。

implicit def myClassPickler[A: SPickler: Unpickler: FastTypeTag](implicit pf: PickleFormat) = 
    new MyClassPickler 
+0

これは動作しますしかし、奇妙な非対称性があります。 'pickle'では、' builder.putField( "myString"、...) 'のようにフィールド名が付けられますが、' unpickle'ではそれらの名前を使用しません。これらの名前はオプションですか?その場合は、どうすれば使用できますか? – emchristiansen

+0

JSONのようないくつかのpickleフォーマットは、フィールド名をpickleに入れます。たとえそれらが未使用のものであったとしても、現在それらを使用することを避ける方法はありません。 APIはまだ少し進化しています。 –

+0

これはjsonではバイナリでしか動作しません。 – Yar

関連する問題