使用匿名参数时,将来的映射会透明地分为两个函数

Raf*_*ter 3 scala future

我被斯卡拉期货观察到的东西困住了,我无法弄清楚这里发生了什么.我正在将未来映射到另一个结果,这里没什么好看的:

import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

object Example extends App {
  val f = Future {
    Thread.sleep(1000)
    println("Future: " + Thread.currentThread + " (" + 
        System.currentTimeMillis + ")")
    "future"
  }
  val g = f map { x =>
    println("Map future: " + Thread.currentThread + 
        " (" + System.currentTimeMillis + ")")
    "mapped " + x
  }
  println(Await.result(g, 5 seconds))
}
Run Code Online (Sandbox Code Playgroud)

由于我映射未来的函数取决于结果f,我希望该函数仅在计算f完成后触发.这也是我用上面的代码可以观察到的.但是,当我更改函数g以携带匿名参数时,此行为会更改:

val g = f map {
  println("Map future: " + Thread.currentThread + " (" + 
      System.currentTimeMillis + ")")
  "mapped " + _
}
Run Code Online (Sandbox Code Playgroud)

即使结果g取决于结果f,该方法在计算f完成之前被触发.看起来好像该方法在实际需要输入值之前和之后被拆分为一部分.此外,线程的第一部分在main中执行.这是编译器在这里做的事吗?对我来说,这非常出乎意料.或者这种行为是否在Scala的某处表达过?但是,我无法在消息来源中找到它.

谁知道这里发生了什么?我正在使用Scala 2.10.

om-*_*nom 10

它可能会让你感到惊讶,但是在lambda构建期间执行println:

List(1,2,3).map { 
    println("Hi!")
    "Processing " + _ 
}

// Hi! 
// res4: List[String] = List(Processing 1, Processing 2, Processing 3)
Run Code Online (Sandbox Code Playgroud)

正如你所看到Hi!的只有一次.

那是因为你的代码在语义上与:

def constructLambda() = {
  // do something, e.g. println
  // now return actual lambda
}
val lambda = constructLambda()
xs map (lambda) // now trigger previously *lazy* piece of code
// or even this, like in your snippet
xs map lambda
Run Code Online (Sandbox Code Playgroud)