假设我有一个ListBuffer[Int]
,我用foreach
循环迭代它,每个循环将从Future
内部修改此列表(删除当前元素),并且列表为空时执行一些特殊操作。示例代码:
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.collection.mutable.ListBuffer
val l = ListBuffer(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
l.foreach(n => Future {
println(s"Processing $n")
Future {
l -= n
println(s"Removed $n")
if (l.isEmpty) println("List is empty!")
}
})
这可能会非常糟糕。我有一个更复杂的代码,具有相似的结构和相同的需求,但我不知道如何构造它,所以我可以更可靠的方式实现相同的功能。
答案 0 :(得分:0)
你提出问题的方式实际上并不属于scala所针对的功能范例。
你似乎想要的是做一个异步计算列表,在每个计算结束时做一些事情,在每个计算结束时做一些事情。如果您使用continuation,这非常简单,使用map
上的flatMap
和Future
方法很容易实现。
val fa: Future[Int] = Future { 1 }
// will apply the function to the result when it becomes available
val fb: Future[Int] = fa.map(a => a + 1)
// will start the asynchronous computation using the result when it will become available
val fc: Future[Int] = fa.flatMap(a => Future { a + 2 })
完成所有这些操作后,您可以在每个Future
完成(成功)后轻松执行某些操作:
val myFutures: List[Future[Int]] = ???
myFutures.map(futInt => futInt.map(int => int + 2))
在这里,我将从List
中的不同异步计算中为每个值添加2。
您还可以选择使用Future
等待列表中的所有Future.sequence
完成:
val myFutureList: Future[List[Int]] = Future.sequence(myFutures)
再一次,您获得Future
,当输入列表中的每个Future
成功解析后,将会解析,或者只要您Future
个失败。然后,您就可以在此新map
上使用flatMap
或Future
,一次性使用所有计算值。
所以我在这里编写你建议的代码:
val l = 1 to 10
val processings: Seq[Future[Unit]] = l.map {n =>
Future(println(s"processing $n")).map {_ =>
println(s"finished processing $n")
}
}
val processingOver: Future[Unit] =
Future.sequence(processings).map { (lu: Seq[Unit]) =>
println(s"Finished processing ${lu.size} elements")
}
当然,我建议使用真正的函数而不是程序(返回Unit
),以便您可以使用值来执行某些操作。我使用println
来生成一个代码,它会产生与你相同的输出(除了印刷品,其含义略有不同,因为我们不再改变任何东西)。