Scala语言规范部分 6.19 说:
A for comprehension
for (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 ...
为什么第二个版本不起作用?或者更确切地说,为什么第一个版本有效?
答案 0 :(得分:4)
如果您在for
- 理解中使用模式匹配,编译器实际上会在filter
之前插入对instanceOf
的调用 - 在应用map
之前进行检查。
编辑:
同样在6.19节中,它说:
如果g被转换为单个生成器,则生成器p&lt; -e后跟保护器p&lt; -e.withFilter((x1,...,xn)=&gt; g)其中x1,... ,xn是p。
的自由变量
生成器先前定义为:
Generator :: = Pattern1'&lt; - 'Expr [Guard]
检查字节码时,您会在调用filter
之前看到map
的来电。
答案 1 :(得分:2)
作为Eastsun评论的补充:Scala 2.8有一个方法收集,可以在你的例子中使用:
l.collect { case Left(x) => x }
//--> List[String] = List(Bad)
答案 2 :(得分:1)
Scala 2.7语言规范,第83页,从底部开始的第二段(这里没有2.8规范)。插入用于生成器模式匹配的过滤器是for-comprehension翻译过程的第一步。
有一点需要注意,我最后一次检查时,这对于打字模式不起作用,这可能会令人惊讶。所以在你的例子中
for(x:Left <- l) yield x
无效,抛出类型错误