Scala 3宏注解中如何将变量名作为字符串传入方法调用?
实现Scala 3.3.4的@MarkNode宏注解
核心实现代码
Scala 3.3.4中宏注解仍属实验特性,需启用-language:experimental.macros编译选项。以下是完整的宏注解实现:
import scala.annotation.experimental import scala.quoted.* @experimental class MarkNode extends scala.annotation.MacroAnnotation: override def transform(using Quotes)(tree: quotes.reflect.Tree): quotes.reflect.Tree = import quotes.reflect.* tree match // 匹配带注解的val定义 case ValDef(varName, _, initExpr) => // 直接获取变量名字符串,无需废弃API val varNameStr = varName.toString // 保留原始val声明 val valDeclaration = ValDef(varName, TypeTree.empty, initExpr).withPos(tree.pos) // 生成setCodegenSuffix调用的表达式 val setSuffixCall = '{ $initExpr.setCodegenSuffix(${ Expr(varNameStr) }) } // 组合成代码块:先声明变量,再调用方法 Block(List(valDeclaration), setSuffixCall.asTerm).withPos(tree.pos) // 处理非val定义的情况 case _ => report.error("@MarkNode仅支持标注val定义", tree.pos) tree
使用示例
假设你的Data类定义如下:
class Data: def setCodegenSuffix(suffix: String): Unit = println(s"为实例设置后缀: $suffix")
标注使用:
@MarkNode val dataAbc = new Data()
编译后会被自动转换为:
val dataAbc = new Data(); dataAbc.setCodegenSuffix("dataAbc")
关键要点说明
- 获取变量名:直接通过
ValDef的varName字段调用toString即可拿到变量名的字符串,完全避开了废弃的'lhs符号字面量和Symbol.apply方法。 - 注入字符串参数:利用
Expr(varNameStr)将变量名字符串转换成可注入引号块的表达式,确保setCodegenSuffix能正确接收变量名字符串参数。 - 保持位置信息:所有生成的语法树都调用
withPos(tree.pos),确保编译错误能定位到原始代码行,提升调试体验。 - 错误处理:如果注解被用在非val定义上,直接抛出明确的编译错误,避免无效转换。
内容的提问来源于stack exchange,提问作者Jelly Terra
相关产品推荐
相关产品推荐

