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
相关产品推荐
相关产品推荐

