[英]Type Erasure in Scala
I'm rather confused about what's happening here: 我对这里发生的事情感到困惑:
import scala.collection.immutable._
object Main extends App {
sealed trait Node
sealed trait Group
case class Sheet(
val splat: String,
val charname: String,
val children: ListMap[String, Node],
val params0: ListMap[String, Param], //params0 to separate sheet-general parameters
val note: Option[Note]
) extends Node with Group
case class Attributes(val name: String) extends Node with Group
case class Param(val name: String, val value: String) extends Node
case class Note(val note: String) extends Node
I've got three versions of a replace function - the last one is the one I'm actually trying to write, the others are just debugging. 我有三个版本的替换功能 - 最后一个是我实际上要编写的,其他只是调试。
class SheetUpdater(s: Sheet) {
def replace1[T <: Group](g: T): Unit = {
s.children.head match {
case (_, _:Sheet) =>
case (_, _:Attributes) =>
}
}
}
This version throws no warnings, so apparently I have access to the type of s.children
at runtime. 这个版本没有警告,所以显然我可以在运行时访问
s.children
的类型。
class SheetUpdater(s: Sheet) {
def replace2[T <: Group](g: T): Unit = {
g match {
case _:Sheet =>
case _:Attributes =>
}
}
}
Neither does this version, so apparently the details of g
's type are also available at runtime... 这个版本也没有,所以显然
g
的类型的细节也可以在运行时使用...
class SheetUpdater(s: Sheet) {
def replace3[T <: Group](g: T): Unit = {
s.children.head match {
case (_, _:T) => //!
case (_, _:Attributes) =>
}
}
}
... but even so, this ends up throwing me the dreaded Abstract type pattern T is unchecked since it is eliminated by erasure
warning. ...但即便如此,这最终会让我感到害怕的
Abstract type pattern T is unchecked since it is eliminated by erasure
警告Abstract type pattern T is unchecked since it is eliminated by erasure
。 What's going on here? 这里发生了什么?
In Scala, generics are erased at runtime, which means that the runtime type of List[Int]
and List[Boolean]
is actually the same. 在Scala中,泛型在运行时被擦除,这意味着
List[Int]
和List[Boolean]
的运行时类型实际上是相同的。 This is because the JVM as a whole erases generic types. 这是因为JVM整体上擦除了泛型类型。 All this is due because the JVM wanted to remain backwards compatible way back when generics were first introduced...
所有这一切都是因为JVM想要在首次引入仿制药时保持向后兼容......
There is a way around this in Scala using a ClassTag
, which is an implicit parameter that then can be threaded around with whatever generic you are using. 在Scala中有一种方法可以使用
ClassTag
,这是一个隐式参数,然后可以使用您正在使用的任何通用线程。
You can think of : ClassTag
as passing the type of the generic as an argument. 您可以将
: ClassTag
视为将泛型的类型作为参数传递。 (It is syntactic sugar for passing an implicit parameter of type ClassTag[T]
.) (它是传递
ClassTag[T]
类型的隐式参数的语法糖。)
import scala.reflect.ClassTag
class SheetUpdater(s: Sheet) {
def replace3[T <: Group : ClassTag](g: T): Unit = {
s.children.head match {
case (_, _:T) => //!
case (_, _:Attributes) =>
}
}
}
Newer answers of this question have more details. 这个问题的新答案有更多细节。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.