如何从Scala泛型参数获取全限定Class对象?
Scala 3中泛型类的Class对象隐式获取问题
问题背景
我需要实现一个接口,在运行时获取泛型类对应的Class对象。以下是我的代码示例:
package com.example import java.util.function.Consumer import scala.reflect.ClassTag import java.util.Collection trait DomObj: def foo(): Unit trait DomObjA extends DomObj: def bar(): Unit /** 这是无法修改的外部Java API */ trait Store: def subscribe[T <: DomObj](cls: Class[T], cons: Consumer[Collection[T]]) = ??? /** 我正在编写的类 */ object Client: val store: Store = ??? def sub1[T <: DomObj](cons: Consumer[Collection[T]])(using classTag: ClassTag[T]): Unit = store.subscribe(classTag.runtimeClass, cons) def sub2[T <: DomObj](cons: Consumer[Collection[T]])(using classTag: ClassTag[T]): Unit = val cls: Class[T] = classTag.runtimeClass.asSubclass(classOf[DomObj]) store.subscribe(cls, cons) def sub3[T <: DomObj](cons: Consumer[Collection[T]])(using classTag: ClassTag[T]): Unit = val cls: Class[T] = classTag.runtimeClass.asSubclass(classOf[T]) store.subscribe(cls, cons) def subSad[T <: DomObj](cls: Class[T], cons: Consumer[Collection[T]]): Unit = store.subscribe(cls, cons) def run(): Unit = val cons: Consumer[Collection[DomObjA]] = ??? sub1(cons) sub2(cons) sub3(cons) subSad(classOf[DomObjA], cons)
subSad方法可以正常工作,但我希望避免显式指定Class对象——编译器已经知道对应的类型,应该能通过隐式参数传递,这也是ClassTag的设计初衷。但其他尝试均无法编译:
sub1编译错误
[error] 30 | store.subscribe(classTag.runtimeClass, cons) [error] | ^^^^^^^^^^^^^^^^^^^^^ [error] | Found: Class[?] [error] | Required: Class[T] [error] | [error] | where: T is a type in method sub1 with bounds <: com.example.DomObj
sub2编译错误
[error] 32 | val cls: Class[T] = classTag.runtimeClass.asSubclass(classOf[DomObj]) [error] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [error] | Found: Class[? <: com.example.DomObj] [error] | Required: Class[T] [error] | [error] | where: T is a type in method sub2 with bounds <: com.example.DomObj
sub3编译错误
[error] 35 | val cls: Class[T] = classTag.runtimeClass.asSubclass(classOf[T]) [error] | ^ [error] | T is not a class type [error] | [error] | where: T is a type in method sub3 with bounds <: com.example.DomObj
Scala 2中的TypeTag似乎能满足需求,但该特性在Scala 3中已移除。有没有可行的实现方式,还是只能使用subSad这种显式传参的方式?
另外,以下代码可以编译通过,但使用了asInstanceOf——虽然我们知道类型转换是安全的,但这通常被视为代码坏味道:
def sub4[T <: DomObj](cons: Consumer[Collection[T]])(using classTag: ClassTag[T]): Unit = val cls: Class[T] = classTag.runtimeClass.asInstanceOf[Class[T]] store.subscribe(cls, cons)
内容的提问来源于stack exchange,提问作者Troy Daniels
相关产品推荐
相关产品推荐

