混合期货和向量以便理解

时间:2017-12-08 23:13:35

标签: scala future

我想迭代一个从未来获得的向量。我希望以下内容能够正常工作,但它会在user <- usersToReview行上出现类型不匹配的编译器错误。

import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration._

object Main3 {
  var counter = 0

  val fUsersToReview: Future[Vector[String]] = Future {Vector("u1", "u2", "u3")}

  def doIt(user: String): Future[Int] = {
    counter = counter + 1
    Future.successful(counter)
  }

  def main(args: Array[String]): Unit = {
    val result:Future[Vector[Int]] = for {
      usersToReview ← fUsersToReview
      user ← usersToReview
      msg_id ← doIt(user)
    } yield {
      msg_id
    }

    println(Await.result(result, 1.second))
  }
}

以下作品,但看起来非常笨重。关于如何改进这个的建议?

  def main(args: Array[String]): Unit = {
    val result:Future[Vector[Int]] = (for {
      usersToReview ← fUsersToReview
    } yield {

      Future.sequence(
        for (u ← usersToReview) yield {
          doIt(u)
        }
      )
    }).flatMap(identity)

    println(Await.result(result, 1.second))
  }
}

2 个答案:

答案 0 :(得分:0)

这是一个不使用for-comprehension而只使用map可能更干净的例子:

val result: Future[Vector[Int]] = fUsersToReview.map(_.map(doIt(_)))

对于OptionEither之类的内容,您可以使用OptionTEitherT等monad转换器,但Vector没有任何内容。< / p>

答案 1 :(得分:0)

感谢关于adrice727答案的见解,我已经找到了问题的解决方案。它涉及重构doIt以获取向量。  通过将向量的处理转移到doIt,向量出于for-comprehension。一旦它只处理期货,它就会按预期工作。

我稍微简化了我的原始帖子,因此以下内容包括for-comprehension中的另一个级别,doIt实际上对它传递的数据做了一些事情。背景是fMaintainersfUsersToReviewdoIt都在数据库上。

val fMaintainers: Future[Vector[String]] = Future {Vector("m1", "m2", "m3")}

val fUsersToReview: Future[Vector[String]] = Future {Vector("u1", "u2", "u3")}

def doIt(users: Vector[String], maintainers: Vector[String]): Future[Vector[(String, String)]] = {
  Future.sequence(for (u ← users) yield {
    Future.successful((u, maintainers.head))
  })
}

val result: Future[Vector[(String, String)]] = for {
  maintainers ← fMaintainers
  usersToReview ← fUsersToReview
  msg_id ← doIt(usersToReview, maintainers)
} yield {
  msg_id
}

println(Await.result(result, 1.second))

最后,关注adrice727的建议,即有时候理解不是正确的工具,这里是地图:

val result:Future[Vector[(String, String)]] = 
      fMaintainers.flatMap { m ⇒ fUsersToReview.flatMap { u ⇒ doIt(u, m) } }