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

Scala 3宏如何提取类extends子句中传递给父trait的构造参数

你需要的父类构造传参信息没有被擦除,可以直接从ClassDef的parents语法树节点中提取,不需要解析源代码。

核心实现逻辑

当类继承带构造参数的trait/类时,ClassDef.parents列表中对应的父节点是Apply类型,它的args字段就是你传入父构造器的所有参数表达式,直接提取这些表达式的标识符名称即可。

完整代码示例

import scala.quoted.*

inline def simpleProductTest[T <: Singleton]: String = ${simpleProductTestImpl[T]}

def simpleProductTestImpl[T](using q: Quotes)(using Type[T]): Expr[String] = {
  import q.reflect.*
  // 获得目标类的符号及对应的语法树
  val targetClass = TypeRepr.of[T].typeSymbol.asClass
  val classDef = targetClass.tree.asInstanceOf[ClassDef]

  // 匹配MyProduct系列父类的构造参数列表
  val parentArgs = classDef.parents.collectFirst {
    case Apply(Select(New(typeTree), "<init>"), args) 
      if typeTree.tpe.typeSymbol.fullName.startsWith("your.package.MyProduct") => args
  }.getOrElse(report.errorAndAbort(s"${targetClass.name} does not extend MyProduct trait"))

  // 提取参数名,仅适配直接传入主构造参数的场景,可自行扩展支持其他表达式
  val paramNames = parentArgs.map {
    case Ident(name) => name
    case expr => report.errorAndAbort(s"Unsupported parent argument expression: $expr")
  }

  // 按需求返回结果,示例返回逗号分隔的参数名字符串
  Expr(paramNames.mkString(","))
}

注意事项

  • 代码中的your.package.MyProduct需要替换为你自己的MyProduct系列trait的实际包名,避免重名误匹配
  • 该方案完全支持同类型多参数场景,因为直接提取参数标识符名称,不依赖类型推导
  • 如果你的业务场景存在向父构造器传入字面量、计算表达式等非类参数的情况,可以扩展匹配规则处理对应表达式类型
  • 你之前查询symbol.declarations和<init>方法找不到对应信息是因为这些入口仅包含类自身的成员定义,父构造传参属于类继承定义的一部分,仅存于ClassDef的parents节点中

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 13:12:04