针对非泛型场景的 Scala 类型擦除警告

问题描述 投票:0回答:1

我正在为 Scala 案例类编写一个自定义序列化器,并有一个实用函数来确定各种符号是否是案例类:

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

def isCaseClass(symbol: ru.Symbol): Boolean = (symbol.isInstanceOf[ru.MethodSymbol] &&
                                                  symbol.asInstanceOf[ru.MethodSymbol].isCaseAccessor) ||
                                                  (symbol.isInstanceOf[ru.ClassSymbol] &&
                                                  symbol.asInstanceOf[ru.ClassSymbol].isCaseClass)

isInstanceOf
检查会导致警告,但我不知道为什么:

abstract type reflect.runtime.universe.MethodSymbol is unchecked since it is eliminated by erasure
abstract type reflect.runtime.universe.ClassSymbol is unchecked since it is eliminated by erasure

我理解涉及泛型时的类型擦除,例如JVM 无法区分

List[Integer]
List[String]
,我们进入类型标签领域来对此类问题进行排序。但就我而言,
MethodSymbol
Symbol
的子类,那么为什么要删除类型呢?

有人可以解释一下吗?

谢谢,

大卫

scala reflection type-erasure scala-reflect
1个回答
0
投票

正如评论中提出的,我最初打算提出这是由类型转换的使用引起的,但是将代码更改为使用模式匹配并没有帮助:

import scala.reflect.runtime.universe.{MethodSymbol, ClassSymbol, Symbol}

def isCaseClass(symbol: Symbol): Boolean =
  symbol match {
    case m: MethodSymbol if m.isCaseAccessor => true
    case c: ClassSymbol if c.isCaseClass     => true
    case _                                   => false
  }

警告仍然存在,但我仍然建议使用模式匹配而不是

isInstanceOf
/
asInstanceOf
(我记得 Scala 的创建者 Martin Odersky 在 Coursera 上的“Scala 函数式编程原理”中提到过)这对语言故意冗长以激励人们使用模式匹配)。

我不是 100% 确定在这种情况下出现警告的具体原因,但一种可能的解释是,由 Symbol 本身支持的实际

thing
可能 出现在通用上下文中,这意味着它是泛型类的参数。因此,编译器无法保证在运行时捕获Symbol
的具体实现,从而导致警告。

作为解决方法,如果您同意在这些信息作为通用参数出现时不被捕获,您可以将类型标记为

@unchecked

,如下所示:

import scala.reflect.runtime.universe.{MethodSymbol, ClassSymbol, Symbol} def isCaseClass(symbol: Symbol): Boolean = symbol match { case m: MethodSymbol @unchecked if m.isCaseAccessor => true case c: ClassSymbol @unchecked if c.isCaseClass => true case _ => false }
您可以在 

Scastie 上使用此代码

© www.soinside.com 2019 - 2024. All rights reserved.