mop*_*pot 0 foreach scala for-comprehension
我想我认为的 for-comprehension 是“为每个 'a' 创建 'x',然后为每个 'b' 对所有变量做一些事情”
for {
a <- Seq(1, 2, 3)
x = "test" + a
b <- Seq(4, 5, 6)
} {
...
}
Run Code Online (Sandbox Code Playgroud)
应该扩展到
Seq(1, 2, 3).foreach { a =>
val x = "test" + a
Seq(4, 5, 6).foreach { b =>
...
}
}
Run Code Online (Sandbox Code Playgroud)
但令人惊讶的是检查-Xprint:parser显示它扩展到
Seq(1, 2, 3).map { a =>
val x = "test" + a
(a, x)
}.foreach { case (a, x) =>
Seq(4, 5, 6).foreach { b =>
...
}
}
Run Code Online (Sandbox Code Playgroud)
我认为它打破了对整个 for-comprehension 中发生的事情的自然理解,因为现在它首先定义三个不同的“x”,然后执行其他内容。如果“x”的定义会产生副作用,那么这可能很关键,那么脱糖的目的是什么map?
这种行为令人惊讶,但它记录在 Scala 规范中:https : //scala-lang.org/files/archive/spec/2.13/06-expressions.html#for-comprehensions-and-for-loops
根据那里的最后一条规则:
生成器 <- 后跟值定义 ? = ? 被转换为以下值对的生成器,其中 和 ? 是新鲜的名字:
Run Code Online (Sandbox Code Playgroud)(, ?) <- for (@ <- ) yield { val ?@? = ?; (, ?) }
所以当有一个值定义时,Scala 总是插入一个新的 for-comprehension with a yield,然后变成map。
如果您用x = "test" + agenerator替换值定义行x <- Seq("test" + a),结果将如预期的那样:
Seq(1, 2, 3)
.foreach(((a) => Seq("test".$plus(a))
.foreach(((x) => Seq(4, 5, 6)
.foreach(((b) => ...))))))
Run Code Online (Sandbox Code Playgroud)