Ausgabe
Ich möchte ein Makro schreiben, um Eigenschaftsnamen einer Klasse zu erhalten. kann das Modul jedoch nicht Symbol
in Anführungszeichen verwenden. Ich erhalte einen Blow-Fehler …
inline def getProps(inline className: String): Iterable[String] = ${ getPropsImpl('className) }
private def getPropsImpl(className: Expr[String])(using Quotes): Expr[Iterable[String]] = {
import quotes.reflect.*
val props = '{
Symbol.classSymbol($className).fieldMembers.map(_.name) // error access to parameter x$2 from
} wrong staging level:
props - the definition is at level 0,
} - but the access is at level 1.
Lösung
Es gibt Kompilierzeit und Laufzeit von Makros. Und es gibt Kompilierzeit und Laufzeit des Hauptcodes. Die Laufzeit von Makros ist die Kompilierzeit des Hauptcodes.
def getPropsImpl... =
'{ Symbol.classSymbol($className).fieldMembers.map(_.name) }
...
ist falsch, weil Scala 3-Makros Bäume in Bäume umwandeln (dh Expr
s in Expr
s, Expr
ist ein Wrapper über einem Baum) (*). Der Baum
Symbol.classSymbol($className).fieldMembers.map(_.name)
innerhalb des Geltungsbereichs der Anwendungsstelle keinen Sinn machen. Symbol
, Symbol.classSymbol
usw. machen hier im Rahmen von Makros Sinn.
def getPropsImpl... =
Symbol.classSymbol(className).fieldMembers.map(_.name)
...
wäre auch falsch, denn className
da es noch keinen Wert gibt, ist es jetzt nur ein Baum.
Ich denke, richtig ist mit.valueOrAbort
import scala.quoted.*
inline def getProps(inline className: String): Iterable[String] = ${getPropsImpl('className)}
def getPropsImpl(className: Expr[String])(using Quotes): Expr[Iterable[String]] = {
import quotes.reflect.*
Expr.ofSeq(
Symbol.classSymbol(className.valueOrAbort).fieldMembers.map(s =>
Literal(StringConstant(s.name)).asExprOf[String]
)
)
}
Verwendungszweck:
// in other file
getProps("mypackage.App.A") //ArraySeq(s, i)
// in other subproject
package mypackage
object App {
case class A(i: Int, s: String)
}
(*) Scala 2-Makros können mehr mit c.eval
. In Scala 3 gibt es ähnliches , staging.run
aber es ist in Makros verboten .
Eigentlich c.eval
(oder verboten staging.run
) kann auch in Scala 3 emuliert werden
Anmerkungen aus dem Unterricht in Scala 3-Makros erhalten
Beantwortet von – Dmytro Mitin
Antwort geprüft von – Mary Flores (FixError Volunteer)