关于scala:为什么在理解中这两个模式匹配之间的行为会有差异?

考虑此Map[String, Any]

1
val m1 = Map(("k1" ->"v1"), ("k2" -> 10))

现在让我们写一个for

1
2
3
scala> for ((a, b) <- m1) println(a + b)
k1v1
k210

到目前为止一切都很好。

现在让我们指定第二个成员的类型:

1
2
3
4
5
scala> for ((a, b: String) <- m1) println(a + b)
k1v1

scala> for ((a, b: Integer) <- m1) println(a + b)
k210

在这里,正如我指定的类型,发生了过滤,这很棒。

现在说我想改用Array [Any]:

1
val l1 = Array("a", 2)

在这里,事情坏了:

1
2
3
4
scala> for (v: String <- l1) println(v)
<console>:7: error: type mismatch;
 found   : (String) => Unit
 required: (Any) => ?

我的双重疑问是:

  • 为什么第二个匹配过滤器也没有?
  • 有没有一种方法可以在第二种情况下不使用肮脏的isInstanceOf来表达这种过滤?

好吧,后一个示例不起作用,因为它没有被指定。关于什么是合理的行为有一些讨论。就个人而言,我希望它能像您一样工作。事实是:

1
2
3
4
val v: String = (10: Any) // is a compile error
(10: Any) match {
    case v: String =>
} // throws an exception

如果您对此不满意,请加入该俱乐部。 :-)这是一种解决方法:

1
for (va @ (v: String) <- l1) println(v)

请注意,在Scala 3中,您可以:

1
for (case v: String <- l1) println(v)


这种指定行为的主要原因是,为了清楚起见,我们希望鼓励人们添加类型注释。如果需要理解,他们可能会选择非常昂贵的过滤器操作,这是我们要避免的陷阱。但是,我同意我们应该使指定某种模式更为容易。一对父母也许就足够了。

1
2
3
4
5
val x: String = y       // type check, can fail at compile time
val (x: String) = y     // pattern match, can fail at run time

for (x: String <- ys)   // type check, can fail at compile time
for ((x: String) <- ys) // pattern match, can filter at run time