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

Scala 3 宏开发:如何获取宏调用所处的封闭模块

Scala 3 宏获取调用所在封闭模块全限定名实现方案

实现核心是利用Scala 3 宏的quoted反射API,获取宏调用点的所有者符号,遍历拿到封闭类/对象的全限定名即可,具体实现如下:

第一步:定义宏接口与实现

你需要将宏的定义和实现拆分,宏实现部分需要使用scala.quoted相关API:

import scala.quoted.*
object SomeMacro:
  // 对外暴露的宏调用接口
  inline def macroCall(inline expr: String): String = ${ macroImpl('expr) }
  // 宏具体实现逻辑
  private def macroImpl(expr: Expr[String])(using Quotes): Expr[String] =
    import quotes.reflect.*
    // 获取宏调用点的符号
    val callSiteSymbol = Symbol.spliceOwner
    // 向上遍历所有者链,找到最近的类/对象/特质符号
    def findEnclosingModule(symbol: Symbol): Symbol =
      if symbol.isClassDef then symbol
      else if symbol.isNoSymbol then report.errorAndAbort("宏调用点不存在封闭模块")
      else findEnclosingModule(symbol.owner)
    val enclosingModule = findEnclosingModule(callSiteSymbol)
    // 直接获取全限定名,格式为 包名.类名
    val fullQualifiedName = enclosingModule.fullName
    // 将常量字符串返回给调用点
    Expr(fullQualifiedName)

第二步:调用验证

你的业务代码直接调用宏即可拿到预期结果:

package foo.bar
class MyClass:
  // 该变量的值编译后就固定为 "foo.bar.MyClass"
  val macroReturnValue = SomeMacro.macroCall("someExpression")
end MyClass

注意事项

  • 宏代码需要和业务调用代码分属不同编译单元,避免出现循环编译错误
  • 如果你需要适配顶层方法、嵌套类等特殊场景,只需要调整findEnclosingModule的终止判断逻辑即可,比如要获取包名就将终止条件改为symbol.isPackageDef
  • 如果调用宏的位置在局部方法、匿名类内部,上述实现会返回最接近的外层封闭类全限定名,符合常规使用需求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 03:57:02