[FIXED] Scala 3-Makro: Klasseneigenschaften abrufen

Ausgabe

Ich möchte ein Makro schreiben, um Eigenschaftsnamen einer Klasse zu erhalten. kann das Modul jedoch nicht Symbolin 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 Exprs in Exprs, Exprist ein Wrapper über einem Baum) (*). Der Baum

Symbol.classSymbol($className).fieldMembers.map(_.name)

innerhalb des Geltungsbereichs der Anwendungsstelle keinen Sinn machen. Symbol, Symbol.classSymbolusw. machen hier im Rahmen von Makros Sinn.

def getPropsImpl... = 
  Symbol.classSymbol(className).fieldMembers.map(_.name)
  ...

wäre auch falsch, denn classNameda 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)

0 Shares:
Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like

[FIXED] Funkenfassade für CaseWhen

Ausgabe Ich versuche, eine Funktion zu erstellen, die wie eine Fassade für die CaseWhenSpark-Funktion wirkt. CaseWhen( branches: Seq[(Expression,…