在 Scala 中,yield
可以使用 for 循环;例如:
val ints: IndexedSeq[Int] = for(i <- 1 to 10) yield i
但我发现yield
不能使用while循环,例如:
while (resultSet.next()) yield new Row(resultSet)
为什么 Scala 是这样设计的?
我在 Google 和 stackoverflow 上搜索过,但找不到答案。
在 Scala 中,yield
可以使用 for 循环;例如:
val ints: IndexedSeq[Int] = for(i <- 1 to 10) yield i
但我发现yield
不能使用while循环,例如:
while (resultSet.next()) yield new Row(resultSet)
为什么 Scala 是这样设计的?
我在 Google 和 stackoverflow 上搜索过,但找不到答案。
因为while循环是java等价的while循环,'for循环'被翻译成函数调用:(<IndexedSeq>.map
如果你使用yield)或<IndexedSeq>.foreach
(如果你不关心结果)。
示例 Scala 代码:
class ForVsWhileLoop {
val dummy = for(i <- 1 to 10) yield i
var dummy2 = Seq.empty[Int]
var i = 0
while(i <= 10)
dummy2 :+= i
}
编译为 (scala -Xprint:parse ForVsWhileLoop.scala):
[[syntax trees at end of parser]] // ForVsWhileLoop.scala
package <empty> {
class ForVsWhileLoop extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
// ***********************************************
// the 'for loop' is translated to a function call
val dummy = 1.to(10).map(((i) => i));
var dummy2 = Seq.empty[Int];
var i = 0;
// *******************
// classic while loop
while$1(){
if (i.$less$eq(10))
{
dummy2.$colon$plus$eq(i);
while$1()
}
else
()
}
}
}
不同之处在于对 for comprehension 的解释,可以看作是一种 DSL。如果有一个yield理解将被转换为使用map和flatMap的东西并收集结果。如果没有 yield 表达式将被转换为使用foreach的东西,迭代所有值而忽略结果。
而另一方面,它只是一个函数,它在满足某个条件之前执行某些操作并且不返回任何内容,即最后的Unit。它只是用于 sied 效果而不是用于返回结果。因此,即使您使用yield,结果也会被丢弃。
您在上面给出的实现使用了迭代器模式,并且与foreach完全一样。
虽然返回Unit,如foreach:
scala> val res : Unit = (1 to 10) foreach {i => i + 1}
而for with yield返回一个结果,其行为类似于 map。
scala> val res : Seq[Int] = (1 to 10) map {i => i + 1}
res: Seq[Int] = Vector(2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
scala> val res = for (i<- 1 to 10) yield i +1
res: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
因为while
像这里描述的那样工作:while-loop-expressions
即 while 循环表达式返回Unit
。
您的yield
值被隐式转换为此Unit
,如下所述:Implicit conversion to Unit type in Scala。
这一切都取决于什么被转换为我们可以“屈服”的捕获状态: