You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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")

关键要点说明

  1. 获取变量名:直接通过ValDef的varName字段调用toString即可拿到变量名的字符串,完全避开了废弃的'lhs符号字面量和Symbol.apply方法。
  2. 注入字符串参数:利用Expr(varNameStr)将变量名字符串转换成可注入引号块的表达式,确保setCodegenSuffix能正确接收变量名字符串参数。
  3. 保持位置信息:所有生成的语法树都调用withPos(tree.pos),确保编译错误能定位到原始代码行,提升调试体验。
  4. 错误处理:如果注解被用在非val定义上,直接抛出明确的编译错误,避免无效转换。

内容的提问来源于stack exchange,提问作者Jelly Terra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 07:31:07