2

Scala 语言规范第6.19节说:

A for comprehensionfor (p <- e) yield e0被翻译为e.map { case p => e0 }

所以...

scala> val l : List[Either[String, Int]] = List(Left("Bad"), Right(1))
l: List[Either[String,Int]] = List(Left(Bad), Right(1))

scala> for (Left(x) <- l) yield x
res5: List[String] = List(Bad)

到现在为止还挺好:

scala> l.map { case Left(x) => x }
<console>:13: warning: match is not exhaustive!
missing combination          Right

       l.map { case Left(x) => x }
             ^
scala.MatchError: Right(1)
    at $anonfun$1.apply(<console>:13)
    at ...

为什么第二个版本不行?或者更确切地说,为什么第一个版本有效?

4

3 回答 3

4

如果您在for-comprehension 中使用模式匹配,编译器实际上会filterinstanceOf应用map.

编辑:

同样在第 6.19 节中它说:

如果将 g 转换为单个生成器 p <- e.withFilter((x1, ..., xn) => g ) ,则生成器 p <- e 后跟保护,其中 x1, ..., xn 是自由变量p。

生成器在前面定义为:

生成器 ::= Pattern1 '<-' Expr [Guard]

在检查字节码时,您将看到对 的调用filter之前的调用map

于 2010-07-27T14:13:46.273 回答
2

作为 Eastsun 评论的补充:Scala 2.8 有一个方法 collect,可以在您的示例中使用:

l.collect { case Left(x) => x }
//--> List[String] = List(Bad)
于 2010-07-27T15:07:49.880 回答
1

Scala 2.7 语言规范,第 83 页,倒数第二段(此处没有 2.8 规范)。为生成器模式匹配插入过滤器是理解翻译过程的第一步。

需要注意的是,我上次检查时,这不适用于键入的模式,这可能令人惊讶。所以在你的例子中

for(x:Left <- l) yield x  

不起作用,抛出类型错误

于 2010-07-27T14:39:49.330 回答