【问题标题】:Scala Pickling and type parametersScala酸洗和类型参数
【发布时间】:2013-09-10 17:50:40
【问题描述】:

我正在使用Scala Pickling,这是一个用于 Scala 的自动序列化框架。 根据author's slides,只要在范围内有隐式Pickler[T],任何类型的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

【问题讨论】:

  • 我最近也对这个项目产生了兴趣(我相信创建者 Heather Miller 在另一篇文章的 Stackoverflow 上提到了它).. 但我找不到很多好的例子来开始。根据我目前使用 Scala 的学习曲线,宏相当复杂,所以我希望有更多的例子。同样适用于 Twitter Chill!
  • 快速浏览一下实现表明您需要的不是scala.tools.nsc.io.Pickler,而是scala.pickling.SPickler(或scala.pickling.DPickler)。只需将您的定义更改为def bar[T: SPickler](t: T) = t.pickle,然后看看效果如何。
  • SPickler 或 DPickler 都不行(见编辑)。
  • 是的,您已经猜到了,但无论如何要确认,您需要scala.pickling.SPickler 或scala.pickling.DPickler。不理会scala.tools.nsc.io.Pickler(Scala 编译器使用它来pickle/unpickle 类文件)
  • 是的,当涉及到处理抽象类型的酸洗框架时,你是对的。感谢您的报告,并与我们在一起:)

标签: scala scala-pickling


【解决方案1】:

是的,正如安迪指出的那样:

您需要 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

【讨论】:

  • 使用酸洗库时,DPickler 会在哪里发挥作用?
【解决方案2】:

查看该项目,您似乎需要 scala.pickling.SPickler 或 scala.pickling.DPickler(分别为静态和动态)才​​能腌制特定类型。

pickle 方法是宏。我怀疑如果你用SPickler 腌制,宏将需要知道你的类的编译时类型。

因此,您可能需要执行以下操作:

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

或者,DPickler 也可以解决问题。我怀疑您仍然需要为您的特定类型编写一些自定义酸洗逻辑。

【讨论】:

    猜你喜欢
    • 2014-05-29
    • 1970-01-01
    • 1970-01-01
    • 2015-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-15
    相关资源
    最近更新 更多