【问题标题】:Difference of scala typed pattern match between Array and ListArray和List之间scala类型模式匹配的区别
【发布时间】:2015-12-20 01:48:01
【问题描述】:

我有以下陈述。

val a: Any = Array("1", "2", "3")
a match {
  case p: Array[Int] => println("int")
  case l: Array[String] => println("string")
}

val b: Any = List(1, 2, 3)
b match {
  case l: List[String] => println("string")
  case p: List[Int] => println("int")
}

关于 Array 的第一个代码块编译时没有警告并输出“string”,而关于 List 的第二个代码块编译时出现与类型擦除相关的警告并输出“string”。

我对 JVM 中的类型擦除有所了解。在运行时,JVM 无法真正知道容器的泛型类型(例如 List)。但是为什么 Array 可以避免运行时的类型擦除并获得正确的类型匹配呢?

我试图从 scala 源代码中找到答案。我唯一发现的是 Array 使用 ClassTag 而 List 没有。

我想了解 ClassTag 的工作原理。 ClassTag 是类型擦除的解决方法吗?以及为什么没有使用 ClassTag 实现像 List 这样的容器以避免类型擦除。

【问题讨论】:

    标签: scala pattern-matching type-erasure


    【解决方案1】:

    Scala 在 JVM 上运行并继承其约束。 Java 使用类型擦除,因此所有参数化类型在运行时都是相同的。类型信息从它们中删除。这样做是为了保持与根本无法使用类型参数的旧 Java 版本的兼容性。

    但数组是 Java 中的特例,它们保存类型信息。所以scala数组可以。这是在数组中保持内存高效的未装箱值所必需的。

    您应该假设所有类型信息在运行时都丢失了。所以使用一些标签来匹配它们。


    ClassTags 与数组换行无关。所有类型信息均由 JVM 自己提供。

    在 Java 中有一种习惯做法是在每次表达类型关系时遇到困难时使用 AnyRef 和动态转换。 Scala 为静态描述类型提供了更多的表达能力,无需运行时转换。 Scala 编码风格鼓励使用重类型结构来保持代码类型安全。

    ClassTags 和TypeTags 是只能用于静态类型代码的工具。它们包含编译器在编译期间派生的类和类型信息。如果它可以静态派生类型,那么它可以为您提供类型标签来访问这些类型。

    当您编写某种库并且不知道如何使用它时,这很有用。因此,您需要 ClassTag 作为隐式参数,编译器将根据提供给函数调用的其他参数使用适当的类型填充它。隐式参数由库代码作为要求放置,并由调用库的外部代码自动填充。

    【讨论】:

    • 很好的答案!所以想法是保持与java数组兼容,scala数组引入ClassTag来实现?
    • 简要解释类标签
    【解决方案2】:

    在这些情况下,您可能需要考虑使用通过 shapeless 获得的 Typeable 类型类进行类型安全转换。例如:

    scala> import shapeless.syntax.typeable._
    import shapeless.syntax.typeable._
    
    scala> val b: Any = List(1, 2, 3)
    b: Any = List(1, 2, 3)
    
    scala> b.cast[List[String]]
    res1: Option[List[String]] = None
    
    scala> b.cast[List[Int]]
    res2: Option[List[Int]] = Some(List(1, 2, 3))
    

    cast[T] 方法可以通过 implicits 添加到每个类型,如果转换失败,则返回 Option[T],其值为 None,如果成功则返回 Some

    如果您喜欢,可以查看Typeable 的源代码。不过,我建议你在做之前先喝杯好咖啡。 :)

    【讨论】:

      猜你喜欢
      • 2015-04-13
      • 2013-10-05
      • 2011-07-05
      • 2018-11-26
      • 1970-01-01
      • 2020-08-09
      • 1970-01-01
      • 2018-08-30
      • 2012-09-02
      相关资源
      最近更新 更多