我非常好奇斯卡拉是如何贬低以下理解的:
for {
a <- Option(5)
b = a * 2
c <- if (b == 10) Option(100) else None
} yield b + c
我的困难来自于产量中b
和c
,因为它们似乎在不同的步骤中受到约束
答案 0 :(得分:4)
这是desugar
的已清理输出 - Ammonite REPL中提供的命令:
Option(5)
.map { a =>
val b = a * 2;
(a, b)
}
.flatMap { case (a, b) =>
(if (b == 10) Option(100) else None)
.map(c => b + c)
}
b
和c
都可以出现在yield
中,因为它不会对链式调用map / flatMap,而是嵌套调用。
答案 1 :(得分:1)
这两个代码是等效的:
scala> for {
| a <- Option(5)
| b = a * 2
| c <- if (b == 10) Option(100) else None
| } yield b + c
res70: Option[Int] = Some(110)
scala> for {
| a <- Option(5)
| b = a * 2
| if (b == 10)
| c <- Option(100)
| } yield b + c
res71: Option[Int] = Some(110)
由于不涉及任何集合,产生多个值,因此只有一个重要的步骤 - 或者说,可以说是3到4个小步骤。如果a为None,则整个循环将提前终止,产生None。
desugaring是一个flatMap / withFilter / map。
答案 2 :(得分:1)
您甚至可以询问编译器。以下命令:
scala -Xprint:parser -e "for {
a <- Option(5)
b = a * 2
c <- if (b == 10) Option(100) else None
} yield b + c"
产生此输出
[[syntax trees at end of parser]] // scalacmd7617799112170074915.scala
package <empty> {
object Main extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
def main(args: Array[String]): scala.Unit = {
final class $anon extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
Option(5).map(((a) => {
val b = a.$times(2);
scala.Tuple2(a, b)
})).flatMap(((x$1) => x$1: @scala.unchecked match {
case scala.Tuple2((a @ _), (b @ _)) => if (b.$eq$eq(10))
Option(100)
else
None.map(((c) => b.$plus(c)))
}))
};
new $anon()
}
}
}
只拍摄你感兴趣的作品并提高可读性,你就明白了:
Option(5).map(a => {
val b = a * 2
(a, b)
}).flatMap(_ match {
case (_, b) =>
if (b == 10)
Option(100)
else
None.map(c => b + c)
})
正如评论中所报道的那样,从编译器输出字面翻译似乎突出了如何呈现desugared表达式的错误。总和应map
表示if
表达式的结果,而不是None
分支中的else
:
Option(5).map(a => {
val b = a * 2
(a, b)
}).flatMap(_ match {
case (_, b) =>
(if (b == 10) Option(100) else None).map(c => b + c)
})
向编译器团队询问这是否是一个错误可能是值得的。