why yield can not work with while loop in scala

血红的双手。 提交于 2019-12-10 09:34:16

问题


In Scala, yield can work with for-loops; for example:

val ints: IndexedSeq[Int] = for(i <- 1 to 10) yield i

But I found that yield can not work with while-loops, e.g. like:

while (resultSet.next()) yield new Row(resultSet)

Why is Scala designed like this?

I have searched on Google and stackoverflow, but could not find an answer.


回答1:


Because a while loop is a java equivalent while loop, and the 'for loop' is translated to function call of: <IndexedSeq>.map (if you use yield) or <IndexedSeq>.foreach (if you don't care the result).

Example Scala Code:

class ForVsWhileLoop {
  val dummy = for(i <- 1 to 10) yield i

  var dummy2 = Seq.empty[Int]
  var i = 0
  while(i <= 10)
    dummy2 :+= i
}

Compiles to (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
        ()
    }
  }
}



回答2:


The difference lies in the interpretation of the for comprehension, which can be seen as a DSL. If there is a yield the comprehension will be translated to something using map and flatMap and collect the results. If there is no yield the expression will be translated to something using foreach, iterating over all values ignoring the results.

While on the other hand is just a function that does something until a certain condition is met and returns nothing, i.e. Unit at the end. It is just called for sied effects and not for returning results. Thus even if you use yield the result will be thrown away.

The implemention you have given above uses the the Iterator pattern and would work exactly like foreach does.

While returns Unit , like foreach :

scala> val res : Unit = (1 to 10) foreach {i => i + 1}

whereas for with yield returns a result and behaves like 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)



回答3:


Because while works like described here: while-loop-expressions i.e. while loop expression returns Unit.

Your yield value is implicitly converted to this Unit as described here: Implicit conversion to the Unit type in Scala .




回答4:


It all depends on what gets converted to a captured state which we can 'yield':

https://docs.scala-lang.org/tutorials/FAQ/yield.html



来源:https://stackoverflow.com/questions/27090229/why-yield-can-not-work-with-while-loop-in-scala

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!