Combining Scala Futures and Collections for Understanding

I try to use a for expression to iterate through a list, and then do the conversion for each item using a utility that returns Future. In short, it does not compile, and I would like to understand why. I read this question , which is similar, and was of great help, but what I'm trying to do is even simpler, which is even more confusing why it does not work. I am 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 I get:

error: type of discrepancy; found: scala.concurrent.Future [Int] required: scala.collection.GenTraversableOnce [?] square <- squareInTheFuture (number) ^

Can someone help me understand why this is not working and what is the best alternative?

+6
source share
5 answers

flatMap requires that the constructors of the types numberList and squareInTheFuture(number) be the same (modulo any implicit conversions that the collection library does). This is not true. Instead, this is a workaround:

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

Future companion object has a traverse method that does exactly what you want:

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

This will start all calculations asynchronously and return a future that will be completed after all these futures are completed.

+9
source

@Right. In 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) 
+3
source

Your understanding is the same as

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

flatMap requires the argument function to return the value of GenTraversableOnce[Int] , however yours returns a Future[Int] , therefore, a mismatch.

+2
source

Change & lt; - on = works. In this case, flatmap / map is not called for the Future object.

  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 } 

Reading this helped me understand how profitability works.

+1
source

Source: https://habr.com/ru/post/958523/


All Articles