我想要写一个宏来获取类的属性名。但不能在引号语句中使用Symbol模块。我被吹错了..。
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.发布于 2022-09-19 12:54:00
宏有编译时间和运行时。主代码有编译时间和运行时间。宏的运行时是主代码的编译时间。
def getPropsImpl... =
'{ Symbol.classSymbol($className).fieldMembers.map(_.name) }
...是不正确的,因为Scala 3宏所做的是将树转换为树(即Exprs转换为Exprs,Expr是树的包装器) (*)。树
Symbol.classSymbol($className).fieldMembers.map(_.name)将没有意义的范围内的应用网站。在宏的范围内,Symbol、Symbol.classSymbol等都是有意义的。
def getPropsImpl... =
Symbol.classSymbol(className).fieldMembers.map(_.name)
...这也是不正确的,因为className作为一个值还不存在,它现在只是一棵树。
我想对.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]
)
)
}用法:
// 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宏可以使用c.eval做更多的事情。在Scala 3中,有类似的事情 staging.run,但是在宏中是已禁用。
实际上,c.eval (或禁止的staging.run)也可以在Scala 3中进行模拟。
https://stackoverflow.com/questions/71687957
复制相似问题