宏扩展内的隐式搜索失败

时间:2019-05-16 07:36:59

标签: scala scala-macros

请考虑对任意对象执行“编码”的特征:

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] 
}

为什么会发生这种情况,有什么方法可以使其起作用?

1 个答案:

答案 0 :(得分:0)

要使其正常运行,您可以尝试以下操作之一:

1)添加上下文绑定

 {
    path: 'search/:SearchText',
    loadChildren: "src/app/views/result-listing/result-listing.module#ResultListingModule"
  },

2)制作宏constructor(private _router: Router){} changeRecent(SearchText: string) { this._router.navigate(['/search', SearchText]) }

3)将隐式实例implicit def apply[R <: Product : Serializer]: Encoder[R] = macro applyImpl[R] def applyImpl[R: c.WeakTypeTag](c: blackbox.Context)(serializer: c.Expr[Serializer[R]]): c.Expr[Encoder[R]] = { import c.universe._ c.Expr[Encoder[R]](q""" new Encoder[${weakTypeOf[R]}] { override def encode(r: ${weakTypeOf[R]}): Array[Byte] = $serializer.serialize(r) } """) } 放入whitebox的伴随对象,而不是要导入的某个对象recordSerializer: Serializer[Record]

4)也许您的示例比实际用例容易,但现在看来您不需要宏了

Record