Scala Pickling и параметры типа

Я использую 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 2.10.2 со скала-травлением 0.8-SNAPSHOT.

Это ошибка или ошибка пользователя?

РЕДАКТИРОВАТЬ 1: та же ошибка возникает с обоими scala.pickling.SPickler а также scala.pickling.DPickler,

РЕДАКТИРОВАТЬ 2: похоже, это ошибка: https://github.com/scala/pickling/issues/31

2 ответа

Решение

Да, как указал Энди:

вам нужен либо 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 может сделать свое дело. Я подозреваю, что вам все равно придется написать собственную логику травления для ваших конкретных типов.

Другие вопросы по тегам