隐式宏。默认隐式值。如何?
Implicit macro. Default implicit value. How?
我都不知道怎么问了
我有一个宏,它为类型 T
创建了一个 IsEnum[T]
的实例。
我正在对其进行测试,并希望确保未找到未密封类型的隐式,或者通常不满足枚举要求的类型。
所以我创建了这个测试方法
def enumOf[T](implicit isEnum:IsEnum[T] = null) = isEnum
然后我确保 enumOf[NotAnEnum] == null
但是,它在编译时失败了。
一件事是宏错误。另一件事是宏只是不适用于给定的案例。创建宏时如何区分?
编辑:我使用了 c.abort
和 c.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
我都不知道怎么问了
我有一个宏,它为类型 T
创建了一个 IsEnum[T]
的实例。
我正在对其进行测试,并希望确保未找到未密封类型的隐式,或者通常不满足枚举要求的类型。
所以我创建了这个测试方法
def enumOf[T](implicit isEnum:IsEnum[T] = null) = isEnum
然后我确保 enumOf[NotAnEnum] == null
但是,它在编译时失败了。
一件事是宏错误。另一件事是宏只是不适用于给定的案例。创建宏时如何区分?
编辑:我使用了 c.abort
和 c.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