8

私が取り組んでいるライブラリーについては、scalaクラスをシリアル化するための効率的で便利でタイプセーフなメソッドを提供する必要があります。理想は、ユーザーがケースクラスを作成できる場合であり、すべてのメンバーがシリアル化可能である限り、それもシリアル化可能であるように見えます。私はシリアル化と逆シリアル化の両方の段階でタイプを正確に知っているので、シリアル化形式の一部として「スキーマ」情報を持っている必要はありません(そしてそうする余裕はありません)(Javaオブジェクトのシリアル化のように)。

私はいくつかのアイデアで遊んでいますが、これはかなり近いようです。ここで私が目にする主な問題は、ユーザーがクラスの「適用」および「適用解除」機能をどのように指定する必要があるかということです。これらは本当に静的な関数なので、コンパイラーにそれを見つけてもらうことができるかどうか疑問に思います。

これが自己完結型の例です:

trait InOut[T] {
  // just keeping things simple, for illustration purposes
  def toWire(x: T): Array[Byte]
  def fromWire(v: Array[Byte] ): T
}

object InOutConversions {
  // Pretend these are implemented properly

    implicit def Int = new InOut[Int] {
      def toWire(x: Int): Array[Byte] = Array[Byte]()
      def fromWire(v: Array[Byte] ): Int = 44
    }

    implicit def String = new InOut[String] {
      def toWire(x: String): Array[Byte] = Array[Byte]()
      def fromWire(v: Array[Byte] ): String = "blah"
    }

    // etc... for all the basic types
}

そして、私はこのような関数が必要です:

def serialize2[T, A1 : InOut, A2 : InOut](unapply : T => Option[Product2[A1, A2]])(obj : T) : Array[Byte] = {
  val product : Product2[A1, A2] = unapply(obj).get 
   implicitly[InOut[A1]].toWire(product._1) ++ implicitly[InOut[A2]].toWire(product._2)
}

これにより、ユーザーは非常に簡単に使用できるようになります。例えば

case class Jesus(a: Int, b: String)
val j = Jesus(4, "Testing")
serialize2 (Jesus.unapply(_)) (j)

しかし、ご覧のとおり、その最後の行は本当にかなり厄介でした。確かにそれを改善することは可能でなければなりませんか?(イエスを考えると、確かに私は「適用されない」静的メソッドを見つけることができます)

4

1 に答える 1

3

特定のケースクラスのコンパニオンオブジェクトを取得する一般的な方法がないため、追加の作業を追加します。3つのオプションがあります。

  1. 構造型を使用することもできますが、パフォーマンスが低下します
  2. 小さな型クラスを使用して、正しいunapplyメソッドを暗黙的に解決できます。
  3. toTupleケースクラスインスタンスにメソッドを追加できます。

例えば:

trait ToTuple2[A1,A2] {
  def toTuple: (A1,A2)
}

case class Jesus(a: Int, b: String) extends ToTuple2[Int,String] {
  val toTuple = (a,b)
}

def serialize2[T <: ToTuple2[A1,A2], A1 : InOut, A2 : InOut](obj : T): Array[Byte] = {
  val product : Product2[A1, A2] = obj.toTuple
  implicitly[InOut[A1]].toWire(product._1) ++ implicitly[InOut[A2]].toWire(product._2)
}

オプション2のコード例:

case class Jesus(a: Int, b: String)

trait Unapply2[T,A1,A2] {
  def asTuple( t: T ): (A1,A2)
}

implicit val UnapJesus = new Unapply2[Jesus,Int,String] {
  def asTuple( j: Jesus ) = Jesus.unapply(j).get
}

def serialize2[T, A1, A2](obj : T)
(implicit unap: Unapply2[T,A1,A2], inout1: InOut[A1], inout2: InOut[A2])  : Array[Byte] = {
  val product : Product2[A1, A2] = unap.asTuple(obj)
  inout1.toWire(product._1) ++ inout2.toWire(product._2)
}

あなたはSBinaryを見る必要があります、それは似ています。

于 2011-10-13T07:06:19.053 に答える