我正在使用Scala Pickling,一个用于Scala的自动序列化框架。根据作者的幻灯片,任何类型的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-pickling 0.8-SNAPSHOT的Scala 2.10.2。
这是错误还是用户错误?
编辑1:scala.pickling.SPickler
和scala.pickling.DPickler
都出现相同的错误。
编辑2:看起来这是一个错误:https://github.com/scala/pickling/issues/31
是的,正如安迪指出的那样:
您需要一个
scala.pickling.SPickler
或一个scala.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
从项目来看,您似乎需要一个scala.pickling.SPickler
或scala.pickling.DPickler
(分别为静态和动态)才能腌制特定类型。
泡菜方法是宏。我怀疑如果你用SPickler
泡菜,宏将需要知道你的类的编译时类型。
因此,您可能需要执行类似于以下内容的操作:
object Foo {
def bar(t: SomeClass1) = t.pickle
def bar(t: SomeClass2) = t.pickle
def bar(t: SomeClass3) = t.pickle
// etc
}
或者,DPickler
可以做到这一点。我怀疑您仍然需要为您的特定类型编写一些自定义酸洗逻辑。