简体   繁体   中英

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. 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) ^

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:

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). That isn't the case here. Instead, this is a traversal:

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

@Lee is correct. 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 :

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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