简体   繁体   English

结合Scala Futures和集合进行理解

[英]Combining Scala Futures and collections in for comprehensions

I'm trying to use a for expression to iterate over a list, then do a transformation on each element using a utility that returns a Future. 我正在尝试使用for表达式迭代列表,然后使用返回Future的实用程序对每个元素进行转换。 Long story short, it doesn't compile, and I'd like to understand why. 长话短说,它不编译,我想了解原因。 I read this question , which is similar, and was a great help, but what I'm trying to do is even simpler, which is all the more confusing as to why it doesn't work. 我读了这个类似的问题 ,这是一个很好的帮助,但我想要做的更简单,更令人困惑的是为什么它不起作用。 I'm trying to do something like: 我正在尝试做类似的事情:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

val numberList = List(1, 2, 3)
def squareInTheFuture(number: Int): Future[Int] = Future { number * number}
val allTheSquares = for {
                          number <- numberList
                          square <- squareInTheFuture(number)
                        } yield { square }

And what I get is: 而我得到的是:

error: type mismatch; 错误:类型不匹配; found : scala.concurrent.Future[Int] required: scala.collection.GenTraversableOnce[?] square <- squareInTheFuture(number) ^ 发现:scala.concurrent.Future [Int] required:scala.collection.GenTraversableOnce [?] square < - squareInTheFuture(number)^

Can someone help me understand why this doesn't work and what the best alternative is? 有人可以帮助我理解为什么这不起作用,最好的选择是什么?

The Future companion object has a traverse method that does exactly what you want: Future伴侣对象有一个traverse方法,可以完全按照您的意愿执行:

val allTheSquares: Future[List[Int]] =
  Future.traverse(numberList)(squareInTheFuture)

This will asynchronously start all the computations and return a future that will be completed once all of those futures are completed. 这将异步启动所有计算并返回一旦所有这些期货完成就将完成的未来。

flatMap requires that the type constructors of numberList and squareInTheFuture(number) are the same (modulo whatever implicit conversions the collection library does). flatMap要求numberListsquareInTheFuture(number)的类型构造函数相同( squareInTheFuture(number)集合库所做的任何隐式转换)。 That isn't the case here. 这不是这种情况。 Instead, this is a traversal: 相反,这是一次遍历:

val allSquaresInTheFuture: Future[List[Int]] =
    Future.traverse(numberList)(squareInTheFuture)

@Lee is correct. @Lee是对的。 As an addition, if you are trying to do parallel computation: 另外,如果您尝试进行并行计算:

  val numberList = List(1, 2, 3)
  val allTheSquares = numberList.par.map(x => x * x)(breakOut)

If you really want Future : 如果你真的想要Future

val allTheSquares: Future[List[Int]] = Future.traverse(numberList)(squareInTheFuture)

Your for comprehension is the same as 你的理解是一样的

val allTheSquares = numberList.flatMap(number => squareInTheFuture(number))

flatMap requires that it's argument function returns a GenTraversableOnce[Int] , however yours returns a Future[Int] , hence the mismatch. flatMap要求它的参数函数返回GenTraversableOnce[Int] ,但是你的返回Future[Int] ,因此不匹配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM