高效序列化案例类

发布于 2024-12-09 17:23:39 字数 1402 浏览 0 评论 0原文

对于我正在开发的库,我需要提供一种高效、方便且类型安全的序列化 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)

你所看到的,最后一行真的很恶心。当然一定有可能对此进行改进吗? (鉴于耶稣,我当然可以找到“取消应用”静态方法)

For a library I'm working on, I need to provide an efficient, convenient and typesafe method of serializing scala classes. The ideal would be if a user can create a case class, and as long as all the members are serializable it should seemlessly be so too. I know precisely the type during both the serializing and deserializing stage so there's no need (and can not afford to) have any "schema" information as part of the seriazation format (like the Java object serialisation).

I've been playing with a few ideas, and this one seems to come pretty close. The major problem I see here, is how the user has to specify class's "apply" and "unapply" function. Since these are really static functions, I'm wondering if it's possible to get the compiler to find it.

Here's a self contained example:

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
}

And then I need a function like this:

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)
}

Which would allow a user to use it pretty easy. e.g.

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

But as you can see, that last line was really quite yuck. Surely it must be possible to improve on that? (Given a Jesus, surely I can find the 'unapply' static method)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

转身泪倾城 2024-12-16 17:23:39

由于没有获取给定案例类的伴生对象的通用方法,因此您将添加一些额外的工作。我看到三个选项:

  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,看起来很相似。

Because don't have a generic way of getting the companion object of a given case class, you will add to do some extra work. I see three options:

  1. You can either use structural typing, but you will loose performance
  2. You can use a small type class to resolve implicitly the correct unapply method.
  3. You can add a toTuple method to the case class instances.

For instance:

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)
}

Code example for option 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)
}

You should have a look at SBinary, it looks similar.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文