Scala酸洗和类型参数

时间:2013-09-10 17:50:41

标签: scala scala-pickling

我正在使用Scala Pickling,这是Scala的自动序列化框架。 根据{{​​3}},只要范围中存在隐式T,就可以对任何类型的Pickler[T]进行腌制。 在这里,我假设她的意思是scala.tools.nsc.io.Pickler。 但是,以下内容无法编译:

import scala.pickling._
import scala.pickling.binary._
import scala.tools.nsc.io.Pickler

object Foo {
  def bar[T: Pickler](t: T) = t.pickle
}

错误是:

[error] exception during macro expansion:
[error] scala.ScalaReflectionException: type T is not a class
[error]     at scala.reflect.api.Symbols$SymbolApi$class.asClass(Symbols.scala:323)
[error]     at scala.reflect.internal.Symbols$SymbolContextApiImpl.asClass(Symbols.scala:73)
[error]     at scala.pickling.PickleMacros$class.pickleInto(Macros.scala:381)
[error]     at scala.pickling.Compat$$anon$17.pickleInto(Compat.scala:33)
[error]     at scala.pickling.Compat$.PickleMacros_pickleInto(Compat.scala:34)

我正在使用Scala 2.10.2进行scala-pickling 0.8-SNAPSHOT。

这是错误还是用户错误?

编辑1:scala.pickling.SPicklerscala.pickling.DPickler都出现同样的错误。

编辑2:看起来这是一个错误:author's slides

2 个答案:

答案 0 :(得分:10)

是的,安迪指出:

  

您需要scala.pickling.SPicklerscala.pickling.DPickler(分别是静态和动态)才​​能挑选特定类型。

这些已经包含在scala.pickling包中,因此只需在通用方法签名中使用它们。

您可以向通用方法添加SPickler上下文绑定,这是完全正确的。你需要的唯一额外的东西(诚然,它有点难看,我们正在考虑删除它)是添加一个FastTypeTag上下文绑定。 (这对于酸洗框架来说是必要的,以了解它试图腌制的类型,例如,它以不同的方式处理基元。)

这是您提供通用酸洗/去除方法所需要做的事情:

请注意,对于unbar方法,您需要提供Unpickler上下文绑定而不是SPickler上下文绑定。

import scala.pickling._
import binary._

object Foo {
  def bar[T: SPickler: FastTypeTag](t: T) = t.pickle
  def unbar[T: Unpickler: FastTypeTag](bytes: Array[Byte]) = bytes.unpickle[T]
}

在REPL中测试,你得到:

scala> Foo.bar(42)
res0: scala.pickling.binary.BinaryPickle =
BinaryPickle([0,0,0,9,115,99,97,108,97,46,73,110,116,0,0,0,42])

scala> Foo.unbar[Int](res0.value)
res1: Int = 42

答案 1 :(得分:3)

看一下这个项目,你似乎需要一个scala.pickling.SPickler或一个scala.pickling.DPickler(分别是静态和动态)来挑选特定的类型。

pickle方法是宏。我怀疑如果你使用SPickler进行pickle,那么宏将需要知道你的类的编译时类型。

因此,您可能需要做类似的事情:

object Foo {
  def bar(t: SomeClass1) = t.pickle
  def bar(t: SomeClass2) = t.pickle
  def bar(t: SomeClass3) = t.pickle
  // etc
}

或者,DPickler可以做到这一点。我怀疑你仍然需要为你的特定类型编写一些自定义酸洗逻辑。