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
。
答案 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
块中的内容。