有效地序列化案例类

Hep*_*tic 8 serialization scala case-class

对于我正在处理的库,我需要提供一种有效,方便且类型安全的序列化scala类的方法.理想情况是,如果用户可以创建一个案例类,并且只要所有成员都是可序列化的,那么它应该也是如此.我确切地知道序列化和反序列化阶段的类型,因此不需要(并且不能承受)任何"模式"信息作为序列化格式的一部分(如Java对象序列化).

我一直在玩一些想法,这个似乎非常接近.我在这里看到的主要问题是用户如何指定类的"apply"和"unapply"功能.由于这些都是静态函数,我想知道是否有可能让编译器找到它.

这是一个自包含的例子:

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
}
Run Code Online (Sandbox Code Playgroud)

然后我需要一个这样的函数:

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)
}
Run Code Online (Sandbox Code Playgroud)

这将允许用户非常容易地使用它.例如

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

但正如你所看到的那样,最后一行非常糟糕.当然有必要改进吗?(鉴于耶稣,我当然可以找到'unapply'静态方法)

par*_*tic 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)
}
Run Code Online (Sandbox Code Playgroud)

选项 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)
}
Run Code Online (Sandbox Code Playgroud)

你应该看看SBinary,它看起来很相似。