简体   繁体   中英

Scala pattern matching and type inference

Could someone explain why the following code compiles?

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

This gives me an (expected) warning about type erasure, but it still compiles. I expected this to throw a type error, like it does if I matched on "foo" instead of Option("foo") .

Thanks!

The code is commented, so let's take a moment to savor that:

  /** 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.
   */

Notice that None is not final, for instance. I know, right?

If you ever try scalac -Ypatmat-debug, the comment here might help:

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

Reachability is almost within reach:

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

But I don't see any promises about what might someday be warnable. For performance reasons? One could also say, why should it warn about an instanceOf[Foo[_]]?

For now, the spec sections 8.2 - 8.4 motivate why matching against Foo[a] is interesting (because of the bounds a acquires). I think I'll go read that again. After some coffee.

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 { ... }

I would assume that the compiler is treating both Option and List as Product , which is why it compiles. As you say, the warning about type erasure is expected. Here's an example that uses another 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")
                  ^

UPDATE w/r/t case classes (because of the comment below):

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

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

I noticed that an error is shown when the class of the value you match is declared as final (and we know that String is final). I still don't know why there's no error without it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM