我正在为 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
的子类,那么为什么要删除类型呢?
有人可以解释一下吗?
谢谢,
大卫
正如评论中提出的,我最初打算提出这是由类型转换的使用引起的,但是将代码更改为使用模式匹配并没有帮助:
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
的具体实现,从而导致警告。作为解决方法,如果您同意在这些信息作为通用参数出现时不被捕获,您可以将类型标记为 ,如下所示:
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 上使用此代码。