隐式宏。默认隐式值。如何?

Implicit macro. Default implicit value. How?

我都不知道怎么问了

我有一个宏,它为类型 T 创建了一个 IsEnum[T] 的实例。

我正在对其进行测试,并希望确保未找到未密封类型的隐式,或者通常不满足枚举要求的类型。

所以我创建了这个测试方法

    def enumOf[T](implicit isEnum:IsEnum[T] = null) = isEnum

然后我确保 enumOf[NotAnEnum] == null

但是,它在编译时失败了。

一件事是宏错误。另一件事是宏只是不适用于给定的案例。创建宏时如何区分?

编辑:我使用了 c.abortc.error,两者都给我相同的结果。

听起来您没有将宏具体化类型设为 class IsEnum 白盒。通常隐式宏应该是 whitebox.

import scala.language.experimental.macros
import scala.reflect.macros.whitebox

trait IsEnum[T]
object IsEnum {
  implicit def mkIsEnum[T]: IsEnum[T] = macro mkIsEnumImpl[T]
  def mkIsEnumImpl[T: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
    import c.universe._
    val typ = weakTypeOf[T]
    val classSymbol = typ.typeSymbol.asClass
    if (!classSymbol.isTrait || !classSymbol.isSealed) c.abort(c.enclosingPosition, s"$typ must be sealed trait")
    val symbols = classSymbol.knownDirectSubclasses
    symbols.collectFirst {
      case symbol if !symbol.isModuleClass || !symbol.asClass.isCaseClass =>
        c.abort(c.enclosingPosition, s"${symbol.asClass.toType} must be case object")
    }
    q"new IsEnum[$typ] {}"
  }
}

def enumOf[T](implicit isEnum: IsEnum[T] = null) = isEnum

用法:

sealed trait A
object A {
  case object B extends A
  case object C extends A
  case class D() extends A
}
enumOf[A] //null

sealed trait A
object A {
  case object B extends A
  case object C extends A
  class D extends A
}
enumOf[A] //null

sealed trait A
object A {
  case object B extends A
  object C extends A
}
enumOf[A] //null

trait A
object A {
  case object B extends A
  case object C extends A
}
enumOf[A] //null

sealed trait A
object A {
  case object B extends A
  case object C extends A
}
enumOf[A] //App$$anon@47f37ef1

宏的运行时间就是主代码的编译时间。如果黑盒宏(即使是隐式黑盒宏)抛出异常,那么在主代码编译期间将出现编译错误。如果白盒隐式宏抛出异常,那么在编译主代码期间隐式将从候选中静默删除。

https://docs.scala-lang.org/overviews/macros/blackbox-whitebox.html