【问题标题】:Scala pattern matching and type inferenceScala 模式匹配和类型推断
【发布时间】:2012-09-02 18:03:05
【问题描述】:

有人能解释一下为什么下面的代码会编译吗?

Option("foo") match {
  case x: List[String] => println("A")
  case _ => println("B")
}

这给了我一个关于类型擦除的(预期的)警告,但它仍然可以编译。我希望这会引发类型错误,就像我匹配 "foo" 而不是 Option("foo") 时那样。

谢谢!

【问题讨论】:

  • 看起来像一个错误。我会举报的。

标签: scala pattern-matching type-inference type-erasure


【解决方案1】:

我假设编译器将OptionList 都视为Product,这就是它编译的原因。正如您所说,有关类型擦除的警告是预期的。这是一个使用另一个产品的示例:

scala> Option("foo") match {
 | case x: Tuple2[String,String] => println("TUPLE")
 | case x: List[String] => println("LIST")
 | case _ => println("OTHER")
 | }
<console>:9: warning: non variable type-argument String in type pattern (String, String)       is unchecked since it is eliminated by erasure
          case x: Tuple2[String,String] => println("TUPLE")
                  ^
<console>:10: warning: non variable type-argument String in type pattern List[String] is unchecked since it is eliminated by erasure
          case x: List[String] => println("LIST")
                  ^

更新 w/r/t 案例类(因为下面的评论):

scala> case class Foo(bar: Int)
defined class Foo

scala> val y: Product = Foo(123)
y: Product = Foo(123)

【讨论】:

  • 好像和Product没什么关系。我将Option("foo") 替换为我自己的带有单个参数的案例类,并且没有错误。
  • 错误,案例类自动扩展产品。查看回复编辑。
  • 好吧,但实际上不必是案例类。通常的非最终类也不会导致错误。
  • @user1296806 是对的,它与方差有关 - 这是一个有趣的极端情况。很抱歉混淆了问题;昨晚很晚才发生在我身上!
【解决方案2】:

我注意到,当您匹配的值的类声明为 final 时会显示错误(我们知道 String 是 final)。我仍然不知道为什么没有它就没有错误。

【讨论】:

    【解决方案3】:

    代码已注释,所以让我们花点时间细细品味:

      /** If we can absolutely rule out a match we can fail early.
       *  This is the case if the scrutinee has no unresolved type arguments
       *  and is a "final type", meaning final + invariant in all type parameters.
       */
    

    例如,请注意 None 不是最终的。我知道,对吧?

    如果你曾经尝试过 scalac -Ypatmat-debug,这里的评论可能会有所帮助:

    https://github.com/scala/scala/pull/650

    可达性几乎触手可及:

    https://issues.scala-lang.org/browse/SI-6146

    但我看不到任何关于哪天可能会被警告的承诺。出于性能原因?也可以说,为什么要对 instanceOf[Foo[_]] 发出警告?

    目前,规范第 8.2 - 8.4 节说明了为什么与 Foo[a] 匹配是有趣的(因为 a 获得的边界)。我想我会再读一遍。喝完咖啡。

    trait Foo[+A]
    final class Fuzz[+A] extends Foo[A]
    final object Fooz extends Foo[Nothing]
    object Futz extends Foo[Nothing]
    
    //error
    Fooz match {
      case x: List[_] => println("A")
      case _ => println("B")
    }
    //no error
    Futz match { ... }
    

    【讨论】:

    • 很好,认为模式匹配器会有些怪癖,但昨晚深夜看不到 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-31
    • 1970-01-01
    • 1970-01-01
    • 2020-08-09
    • 2021-08-24
    • 2013-03-17
    • 2015-04-30
    相关资源
    最近更新 更多