【问题标题】:Scala Type Erasure on Option Match选项匹配时的 Scala 类型擦除
【发布时间】:2013-09-07 09:54:14
【问题描述】:
object Test {
  def main(args: Array[String]) {
    val list: List[Double] = List(1.0, 2.0, 3.0, 4.0)
    val none = None

    case class Test()

    val test = Test()

    def f(x: Any) = x match {
        case _: Some[Test] => println("_ matched")
        case None => println("None matched")
    }

    f(list)
    f(none)
    f(test)
  }
}

尝试编译上述代码会导致“被擦除消除”编译时警告。

   $>scalac Test.scala
    Test.scala:11: warning: non-variable type argument Test in type pattern
 Some[Test] is unchecked since it is eliminated by erasure
            case _: Some[Test] => println("_ matched")
                    ^
    one warning found

我阅读了这篇备受推崇的 Stackoverflow post,但我不明白这里的类型擦除。

【问题讨论】:

    标签: scala


    【解决方案1】:

    这是警告您,在运行时无法确定该值是 Some[Test] 还是 Some[Int]Some[anything else]。这是由于 JVM 不知道类型参数(即与我们在 Java 中进行类型擦除的原因相同)。您引用的帖子显示了 Scala 提供的解决此类型擦除问题的方法,如果您真的需要确保您有一个 Some[Test] 而不是 Some 的任何其他子类型。就您而言,这似乎无关紧要,因此我不会发出警告。

    另一方面,更惯用(且实用!)如下:

    def f(x: Any) = x match {
        case Some(y) => println(s"x matched to Some - wrapped value is $y")
        case None => println("None matched")
    }
    

    这与Some[Any] 匹配,但也提供了包装值供您直接在 case 块内使用。

    如果您确实需要确保您的值是 Test 类型,请尝试围绕 TypeTags(例如您提到的链接,或参见here),或者您可以使用有点讨厌的 isInstanceOf 方法:

    case Some(y) if (y.isInstanceOf[Test]) => ...
    

    编辑:或

    case Some(e: Test) => ...
    

    根据@senia 的回答。

    【讨论】:

    • 为什么instanceof 被认为是讨厌的?
    • @Kevin: 如果你想使用y 作为Test 的实例,你应该检查它是否是使用isInstanceOf 的实例,然后使用asInstanceOf 将其转换为Test。它很冗长。而且asInstanceOf 不是类型安全的:编译器不会强制你在asInstanceOf 之前使用isInstanceOf。结构模式匹配是类型安全的:如果你在做一些危险的事情,你会收到警告。
    【解决方案2】:

    jvm 的运行时中没有Some[Test]Some[String] 只有Some[Any]。所以你不能匹配Some[Test]

    在这种情况下,您可以像这样匹配Some 的内容:

    case Some(e: Test) => println(s"$e matched")
    

    【讨论】:

    • 所以在运行时JVM不知道Some(Int)和Some(String)的区别,但是它可以在Some(x)中查找x的type?跨度>
    • @Kevin:是的,就像任何其他变量类型一样。 Scala 编译器将case Some(e: Test) 重写为if (arg.isInstanceOf[Some[_]] && arg.asInstanceOf[Some[Any]].get.isInstanceOf[Test]) { val e = arg.asInstanceOf[Some[Any]].get.asInstanceOf[Test] ... }
    猜你喜欢
    • 1970-01-01
    • 2018-01-30
    • 2018-04-12
    • 2015-10-06
    • 1970-01-01
    • 2016-01-24
    • 2012-05-28
    • 1970-01-01
    • 2019-04-10
    相关资源
    最近更新 更多