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