В следующих двух функциях someF1 не будет компилироваться, но someF2 будет. Это потому, что ожидается, что someF1 вернет Future[Int], но он возвращает Future[Future[Int]], потому что я использую for в for. Я не сталкиваюсь с проблемой в someF2, потому что я выравниваю Future[Future[]] в someF2. Есть ли эквивалентный способ сглаживания результатов, если я использую встроенный for или someF1 неверный вариант использования for, и я должен использовать его только для параллельного выполнения Futures и не по порядку?

  // Start writing your ScalaFiddle code here
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

def someF1:Future[Int] = {
  val f1 = Future[Int]{1}

  for(i<-f1) yield{
    if(i == 0) {
      val f2 = Future{2}
      for(j<-f2) yield {i+j} //this will make function return Future[Future[Int]]
    }
    else {
      val f3 = Future{3}
      for(k<-f3) yield {i+k}//this will make function return Future[Future[Int]]
    }
  }
}

// Start writing your ScalaFiddle code here
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

def someF2:Future[Int] = {
  val f1 = Future[Int]{1}

  f1.flatMap{i=> //flatMap will flatten Future[Future[Int]]
    if(i == 0) {
      val f2 = Future{2}
      f2.map(j=> {i+j})
    }
    else {
      val f3 = Future{3}
      f3.map(k=>{i+k})
    }
  }
}
0
Manu Chadha 17 Сен 2018 в 22:49

2 ответа

Лучший ответ

Правило состоит в том, что при понимании for последний генератор (т.е. <-) переводится в вызов map(). Любой другой генератор - это вызов flatMap(). Итак, нет, вы не можете достичь того, что вы использовали вложенные for. Это создает слишком много вызовов map() и недостаточно вызовов flatMap().

Это будет работать:

def someF1:Future[Int] = {
  val f1 = Future[Int]{1}

  for {
    i <- f1
    j <- Future(2)
    k <- Future(3)
  } yield {
    if (i == 0) i+j
    else        i+k
  }
}

Но в этом случае вы запускаете на один Future больше, чем вам нужно.

2
jwvh 17 Сен 2018 в 20:31

Дополняя ответ @ jwvh

Вы все еще можете избежать второй оценки в будущем с помощью следующего, более сложного фрагмента кода:

def someF1:Future[Int] =
  for {
    i <- Future[Int]{1}
    r <- if (i == 0) {
        for (j <- Future[Int]{2}) yield i + j
      } else {
        for (k <- Future[Int]{3}) yield i + k
      }
  } yield r

Кроме того, я бы порекомендовал вам взглянуть на документацию for / yield

1
Luis Miguel Mejía Suárez 17 Сен 2018 в 20:41