forawait的冲突

Scala提议标准scala.async有个缺陷:不支持for循环1。比如,类似这样的代码无法编译:

import scala.async.Async._
val xs = Seq(1, 2, 3)
async {
  for (x <- xs) {
    await(async(x * 2)) // 编译错误
  }
}

我们的Stateless Future也存在类似的问题,以下代码也不能编译:

import com.qifun.statelessFuture.Future
val xs = Seq(1, 2, 3)
Future {
  for (x <- xs) {
    Future(x * 2).await // 编译错误
  }
}

冲突的原因

这是因为,Scala语言的for语句会被转换成foreachmapflatMapwithFilter函数调用。而for的内部语句块会转换成一个函数对象。比如上述代码相当于

import com.qifun.statelessFuture.Future
val xs = Seq(1, 2, 3)
Future {
  xs.map { x =>
    Future(x * x).await // 编译错误
  }
}

由于上述代码中的await位于匿名函数{ x => ... }中,所以await与外层Future的关联就会阻断,最终导致编译错误。

futureSeq包装函数

幸好,Stateless Future的工具库中,有个futureSeq函数可以解决awaitfor的冲突。只要给xs包装一层futureSeq就可以了。

import com.qifun.statelessFuture.Future
import com.qifun.statelessFuture.util.AwaitableSeq.futureSeq
val xs = Seq(1, 2, 3)
Future {
  val xs2 = for (x <- futureSeq(xs)) {
    Future(x * x).await // 编译通过
  }
}

futureSeq 也支持for/yield推导式:

import com.qifun.statelessFuture.Future
import com.qifun.statelessFuture.util.AwaitableSeq.futureSeq
val xs = Seq(1, 2, 3)
Future {
  val xs2 = for (x <- futureSeq(xs)) yield {
    Future(x * x).await // 编译通过
  }
}

(待续)


  1. Github上的相关问题讨论:scala/async#32


杨博

岂凡 游戏架构师