Future是指尚未完成的操作。在异步编程中,这些操作结果将来会在操作完成后,再传给回调函数。换句话说,一个Future对象,就是一张将来可能兑现的欠条。
在Stateless Future框架中,欠条对应类型为com.qifun.statelessFuture.Future[AwaitResult]。其中,AwaitResult
类型参数表示,欠条兑现时,将会给付的结果类型。
兑现欠条
有两种语法等待一张欠条兑现,await语法和for
推导式1语法。
用await等待欠条兑现
await方法的语义是暂停执行流,一直等到欠条兑现才返回,其返回值就是欠条兑现的结果。我在前一节中讲过,await会被Future宏替换成onComplete,并不真正阻塞线程:
Nio2Future.connect(socket, new InetSocketAddress("www.qifun.com", 80)).await
readAll(socket, response).await
writeAll(socket, request).await
在上述例子中,await表示顺序等待操作,必须出现在Future块中。如果在Future外使用await,就会导致`await` must be enclosed in a `Future` block
的编译错误。
嵌套函数
需要注意,在Future块中的内嵌函数中,一般也不能用await:
val myFuture = Future {
def nestedFunction() = {
anotherFuture.await // 编译错误!
}
nestedFunction()
}
幸好Future可以嵌套,所以你可以这样写:
val myFuture = Future {
def nestedFunction() = Future {
anotherFuture.await // 编译通过
}
nestedFunction().await
}
用for
等待欠条兑现
欠条兑现的另一语法借用了Scala的for
关键字:
println("即将开始等待myFuture")
for (result <- myFuture) {
println(s"结果是:$result")
}
println("正在等待myFuture……")
注意,此处的for
语句并不是循环!for
代码块内是欠条兑现后才触发的代码,通常只触发一次。而for
代码块之后的代码则在开始等待myFuture
以后,马上执行。
所以,大多数情况下,上述代码的输出顺序将会类似这样:
即将开始等待myFuture
正在等待myFuture……
结果是:<myFuture兑现后的结果>
等待多张欠条
还可以用for
语句顺序等待多张欠条:
println("即将开始等待myFuture1")
for (result1 <- myFuture1; result2 <- getMyFuture2(result1)) {
println(s"结果是:$result1、$result2")
}
println("正在等待myFuture1和getMyFuture2(result1)……")
上述代码中,两张欠条依次等待。其中第二张欠条getMyFuture2(result1)
甚至是利用第一张欠条的兑现结果result1
才能计算得到。
欠条的映射和合并
你也可以用for
/yield
语法,把多张欠条合成一张:
case class MyResult(result1: Result1, result2: Result2)
val myFuture3: Future[MyResult] = for (result1 <- myFuture1; result2 <- getMyFuture2(result1)) yield {
MyResult(result1, result2)
}
用for
/yield
创建的欠条,属于无状态欠条,支持惰性执行。创建这张新欠条时并不会发起myFuture
或getMyFuture2(result1)
所对应的异步操作,而要等到对新欠条调用await或者不含yield
的for
时,才会发起操作:
for (result3 <- myFuture3) {
println(s"最终结果是:${result3.result1}、${result3.result2}")
}
当然,你也可以用前面学过的Future/await来合并欠条。以下代码与上方的for
/yield
示例,功能完全相同:
case class MyResult(result1: Result1, result2: Result2)
val myFuture3: Future[MyResult] = Future[MyResult] {
val result1 = myFuture1.await
val result2 = getMyFuture2(result1).await
MyResult(result1, result2)
}
(待续。下一节将会讲解无状态欠条和有状态欠条的区别。)
-
for
推导式即For Comprehension。Scala的for
推导式语法类似命令式语言的for
循环,但语义却更接近Ruby、Python等语言的列表推导式(List Comprehension)。 ↩
- 栏目
- 程序设计 (7)