Рассмотрим черту, которая выполняет «кодирование» произвольных объектов:
trait Encoder[R] {
def encode(r: R): Array[Byte]
}
Предполагая, что кодирование примитивных типов известно, и пользовательские типы могут быть закодированы путем определения «сериализатора»:
trait Serializer[T] {
def serialize(r: T): Array[Byte]
}
мы можем реализовать макрос для кодирования класса дел, просто зациклив поля и неявно просматривая сериализаторы типов. Вот фиктивная реализация, которая ищет сериализатор для самого R
(в действительности мы ищем сериализаторы для типов полей класса case):
object Encoder {
implicit def apply[R <: Product]: Encoder[R] = macro applyImpl[R]
def applyImpl[R: c.WeakTypeTag](c: blackbox.Context): c.Expr[Encoder[R]] = {
import c.universe._
c.Expr[Encoder[R]](q"""
new ${weakTypeOf[Encoder[R]]} {
override def encode(r: ${weakTypeOf[R]}): Array[Byte] =
implicitly[_root_.Serializer[${weakTypeOf[R]}]].serialize(r)
}
""")
}
}
Теперь определите базовый «процессор»:
abstract class BaseProcessor[R: Encoder] {
def process(r: R): Unit = {
println(implicitly[Encoder[R]].encode(r).length)
}
}
И попробуйте использовать это:
case class Record(i: Int)
object Serializers {
implicit def recordSerializer: Serializer[Record] =
(r: Record) => Array.emptyByteArray
}
import Serializers._
class Processor extends BaseProcessor[Record]
Это не скомпилируется с:
// [error] Loader.scala:10:22: could not find implicit value for parameter e: Serializer[Record]
// [error] class Processor extends BaseProcessor[Record]
// [error] ^
// [error] one error found
Однако компилируются следующие компоненты:
class Processor extends BaseProcessor[Record]()(Encoder[Record]) // Compiles!
object x { class Processor extends BaseProcessor[Record] } // Compiles!
Я не могу понять, почему это происходит, похоже, что это как-то связано с определением Processor
, являющимся определением верхнего уровня, поскольку, как только я перемещаю его в класс / объект, все работает, как ожидалось. Вот еще один пример, который не компилируется:
object x {
import Serializers._ // moving the import here also makes it NOT compile
class Processor extends BaseProcessor[Record]
}
Почему это происходит и есть ли способ заставить его работать?