Implizites Makro. Impliziter Standardwert. Wie?
Ich weiß nicht einmal, wie ich die Frage stellen soll.
Ich habe ein Makro, das eine Instanz IsEnum[T]für einen Typ erstellt T.
Ich teste es und möchte sicherstellen, dass das Implizite nicht für Typen gefunden wird, die nicht versiegelt sind oder die im Allgemeinen nicht den Anforderungen einer Aufzählung entsprechen.
Also habe ich diese Methode zum Testen erstellt
def enumOf[T](implicit isEnum:IsEnum[T] = null) = isEnum
Und dann sorge ich dafür enumOf[NotAnEnum] == null
Stattdessen schlägt es beim Kompilieren fehl.
Eine Sache ist das Makrofehler. Eine andere Sache ist, dass das Makro für einen bestimmten Fall einfach nicht gilt. Wie kann man diese Unterscheidung beim Erstellen von Makros treffen?
Bearbeiten: Ich habe verwendet c.abortund c.errorbeide geben mir die gleichen Ergebnisse.
Antworten
Klingt so, als hätten Sie Ihre Makro-Materialisierungs-Typklasse- IsEnumWhitebox nicht erstellt. Normalerweise sollten implizite Makros Whitebox sein.
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
Verwendung:
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$1@47f37ef1
Die Laufzeit von Makros ist die Kompilierungszeit des Hauptcodes. Wenn ein Blackbox-Makro (sogar ein implizites Blackbox-Makro) eine Ausnahme auslöst, handelt es sich beim Kompilieren des Hauptcodes um einen Kompilierungsfehler. Wenn ein implizites Whitebox-Makro eine Ausnahme auslöst, wird das implizite Makro während der Kompilierung des Hauptcodes stillschweigend von den Kandidaten entfernt.
https://docs.scala-lang.org/overviews/macros/blackbox-whitebox.html