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

