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

Scala 3元编程:泛型类实例创建问题(服务发现场景)

Scala 3元编程实例化Trait所有实现类的问题修复

问题背景

要基于Scala 3实现简易服务发现,通过元编程自动实例化MyTrait的所有实现类(ClassA、ClassB)。目前代码能正确识别出这两个子类,但New(TypeTree.of[T])会尝试创建MyTrait实例而非具体子类,导致无法生成目标对象。

问题根源

TypeTree.of[T]生成的是父类型MyTrait的抽象类型树,而不是当前遍历到的具体子类(ClassA/ClassB)的类型树。Scala不允许直接实例化Trait,因此这行代码本质是在尝试做非法操作,自然无法生成正确的子类实例。

解决方案

针对每个找到的子类Symbol,使用它自身的typeRef生成对应的TypeTree,而非复用父类T的类型。这样New操作就会针对具体子类执行,调用无参构造器生成实例。

修改核心代码中的实例化逻辑:

// 原错误代码
Apply(Select(New(TypeTree.of[T]), constructor), Nil).asExprOf[T]

// 修改后的正确代码
Apply(Select(New(TypeTree(symbol.typeRef)), constructor), Nil).asExprOf[T]

完整修复后的核心代码

inline def findImplementations[T]: List[T] = ${ findImplementationsImpl[T] }

private def findImplementationsImpl[T: Type](using q: Quotes): Expr[List[T]] =
    import quotes.reflect.*
    val targetType = TypeRepr.of[T]

    val rootPackage = Symbol.requiredPackage("camundala.worker")

    val implementations: List[Symbol] = rootPackage.declarations
      .collect {
        case cls: ClassDef
            if cls.isClassDef &&
              cls.typeRef.derivesFrom(targetType.typeSymbol) &&
              !cls.flags.is(Flags.Trait) =>
          cls
      }
      .distinct

    val instanceExprs: List[Expr[T]] = implementations.map { symbol =>
      val constructor: Symbol = symbol.primaryConstructor
      val params              = constructor.paramSymss.flatten
      if params.isEmpty then
        // 使用子类自身的typeRef生成TypeTree,确保实例化具体子类
        Apply(Select(New(TypeTree(symbol.typeRef)), constructor), Nil).asExprOf[T]
      else
        report.errorAndAbort(s"无法实例化${symbol.name}:该类无合适的无参构造方法")
      end if
    }
    Expr.ofList(instanceExprs)
end findImplementationsImpl

验证效果

修改后,元编程会生成如下等价代码:

List(new ClassA(), new ClassB())

这样就能正确实例化所有MyTrait的子类,实现服务发现的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 02:50:08