Scala 反射 - MethodSymbol 擦除警告,除非导入 universe._

Scala Reflection - MethodSymbol erasure warning unless importing universe._

我有一个带有泛型类型参数的 class,我想获取对泛型类型构造函数的引用。

如果我导入整个 scala.reflect.runtime.universe._,而不是导入别名(例如 "ru"),这只会在没有擦除警告的情况下起作用。

我不清楚是什么原因。我怀疑必须从 Universe 将隐式引入范围,但尚未通过 IntelliJ 的隐式工具找到任何相关内容。

谁能告诉我为什么会这样,如果是隐含的,是哪一个?

编译时没有警告:

import scala.reflect.runtime.universe._

class CaseClassesExample[T :TypeTag] {

  def doWork: Unit = {
    val tpe = weakTypeTag[T].tpe

    val ctor = tpe.decls.collectFirst {
      case m: MethodSymbol if m.isPrimaryConstructor => m
    }
  }
}

编译时带有 MethodSymbol 的擦除警告:

import scala.reflect.runtime.{universe => ru}

class CaseClassesExample[T : ru.TypeTag] {

  def doWork: Unit = {
    val tpe = ru.weakTypeTag[T].tpe

    val ctor = tpe.decls.collectFirst {
      case m: ru.MethodSymbol if m.isPrimaryConstructor => m
    }
  }
}

警告:

[warn] abstract type pattern reflect.runtime.universe.MethodSymbol is unchecked since it is eliminated by erasure
[warn]       case m: ru.MethodSymbol => m.isConstructor && m.isPrimaryConstructor  
[warn]                  ^

拆分导入:

为了缩小范围,我将导入拆分如下 - 有趣的是,IntelliJ 声明第二个导入未使用,但删除它会带回警告:

import scala.reflect.runtime.{universe => ru}

class CaseClassesExample[T : ru.TypeTag] {

  def doWork: Unit = {
    val tpe = ru.weakTypeTag[T].tpe

    import scala.reflect.runtime.universe._
    //IntelliJ highlights above import as unused - but removing it brings warning back

    val ctor = tpe.decls.collectFirst {
      case m: ru.MethodSymbol if m.isPrimaryConstructor => m
    }
  }
}

原因很简单。 Universe 有一个名为 MethodSymbolTag 的隐式方法(从 Symbols 特性中混入)定义如下:

implicit val MethodSymbolTag: ClassTag[Universe.MethodSymbol]

作用域中 ClassTag[Universe.MethodSymbol] 的存在允许编译器阻止擦除。

您可以通过在第二个代码片段中添加此导入来验证这一点:

import ru.MethodSymbolTag