如何理解`for`和`yield`中的“println”语句

时间:2014-05-01 12:36:01

标签: scala for-loop map

Scala代码:

val list = List(1, 2, 3)
for {
  item <- list
  _ = println("1111111111")
} yield {
  println("XXXXXXXXX")
  item + 1
}

我希望它能打印出来:

1111111111
XXXXXXXXX
1111111111
XXXXXXXXX
1111111111
XXXXXXXXX

但实际上它会打印出来:

1111111111
1111111111
1111111111
XXXXXXXXX
XXXXXXXXX
XXXXXXXXX

我无法理解这一点,因为我认为代码会扩展为:

val list = List(1, 2, 3)
list.map { item =>
  val _ = println("1111111111")
  println("XXXXXXXXX")
  item + 1
}

哪个应该在每个循环中XXXXXXXX之前打印11111111

2 个答案:

答案 0 :(得分:6)

Scala规范,第6.19节 “对于理解和循环”,清楚地描述了行为:

  

生成器p&lt; - e后跟值定义p'= e'被转换为   跟随值对的生成器,其中x和x'是新名称:

(p, p') <- for ( x@p <- e ) yield { val x'@p' = e' ; (x, x') }

例如,代码

for {x <- xs; y = 1} yield {x+y}

去了

xs.map{x => val y = 1; (x,y)}.map{ case (x,y) => x+y}

在你的情况下,它将是

xs.map{x => val x$1 = println("1"); (x,x$1)}.map{ case (x,_) => x+1}

将元组的第二个值丢弃。

答案 1 :(得分:1)

您所看到的是map函数的以下desugar:

def map[B](f: A => B)(implicit cbf: CanBuildFrom[B, List[A], List[B]]): List[B] ={
  val b = new ListBuffer[B]
  var xs = this
  while(!xs.isEmpty){
    b += f(xs.head) //calls "f" here which activates the println
    xs = xs.tail
  }
  b result ()
}

实际上首先通过连续调用f然后迭代地创建新列表的每个元素,它返回创建的列表。请注意,在这种情况下,f不是收益率中的值。除了for for comprehension body之外,这是另一个被调用的函数。

因此,它会在之前打印出"1111111" ,它会返回您希望看到的结果,然后是yield块中的内容。