Scala 中的类型擦除 [英] Type Erasure in Scala

查看:78
本文介绍了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) =>
      }
    }
  }

这个版本没有抛出任何警告,所以显然我可以在运行时访问 s.children 的类型.

This version throws no warnings, so apparently I have access to the type of s.children at runtime.

  class SheetUpdater(s: Sheet) {
    def replace2[T <: Group](g: T): Unit = {
      g match {
        case _:Sheet =>
        case _:Attributes =>
      }
    }
  }

这个版本也没有,所以显然g的类型的细节在运行时可用...

Neither does this version, so apparently the details of g's type are also available at runtime...

  class SheetUpdater(s: Sheet) {
    def replace3[T <: Group](g: T): Unit = {
      s.children.head match {
        case (_, _:T) => //!
        case (_, _:Attributes) =>
      }
    }
  }

...但即便如此,这最终还是让我感到可怕的抽象类型模式 T 未被检查,因为它被擦除警告消除了.这是怎么回事?

... but even so, this ends up throwing me the dreaded Abstract type pattern T is unchecked since it is eliminated by erasure warning. What's going on here?

推荐答案

在 Scala 中,泛型在运行时被擦除,这意味着 List[Int]List[Boolean] 其实是一样的.这是因为 JVM 作为一个整体擦除了泛型类型.这一切都是因为 JVM 希望在首次引入泛型时保持向后兼容......

In Scala, generics are erased at runtime, which means that the runtime type of List[Int] and List[Boolean] is actually the same. This is because the JVM as a whole erases generic types. All this is due because the JVM wanted to remain backwards compatible way back when generics were first introduced...

在 Scala 中有一种使用 ClassTag 的方法来解决这个问题,这是一个隐式参数,然后可以与您正在使用的任何泛型进行线程化.

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.

您可以将 : ClassTag 视为将泛型类型作为参数传递.(它是传递 ClassTag[T] 类型的隐式参数的语法糖.)

You can think of : ClassTag as passing the type of the generic as an argument. (It is syntactic sugar for passing an implicit parameter of type 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) =>
    }
  }
}

此问题的较新答案有更多详细信息.

这篇关于Scala 中的类型擦除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆