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

如何从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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 13:56:00