在理解中混合期货和向量
Mixing futures and vectors in a for comprehension
我想迭代从未来获得的向量。我希望下面的工作正常,但它在 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))
}
}
这是一个不使用 for-comprehension
而只使用 map
:
可能更干净的例子
val result: Future[Vector[Int]] = fUsersToReview.map(_.map(doIt(_)))
对于 Option
和 Either
这样的东西,你可以使用像 OptionT and EitherT 这样的 monad 转换器,但是 Vector
.
没有任何东西
多亏了adrice727的回答的思考,我找到了解决问题的办法。它涉及重构 doIt
以获取向量。
通过将向量的处理转移到 doIt
,向量从 for-comprehension 中出来。一旦它只处理期货,它就会按预期工作。
我已经稍微简化了我原来的 post,所以下面的内容在 for-comprehension 中增加了一个级别,并且 doIt
实际上对它传递的数据做了一些事情。其背景是fMaintainers
、fUsersToReview
、doIt
都是作用于一个数据库。
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 的建议,即有时 for-comprehensions 不是正确的工具,这里是地图:
val result:Future[Vector[(String, String)]] =
fMaintainers.flatMap { m ⇒ fUsersToReview.flatMap { u ⇒ doIt(u, m) } }
我想迭代从未来获得的向量。我希望下面的工作正常,但它在 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))
}
}
这是一个不使用 for-comprehension
而只使用 map
:
val result: Future[Vector[Int]] = fUsersToReview.map(_.map(doIt(_)))
对于 Option
和 Either
这样的东西,你可以使用像 OptionT and EitherT 这样的 monad 转换器,但是 Vector
.
多亏了adrice727的回答的思考,我找到了解决问题的办法。它涉及重构 doIt
以获取向量。
通过将向量的处理转移到 doIt
,向量从 for-comprehension 中出来。一旦它只处理期货,它就会按预期工作。
我已经稍微简化了我原来的 post,所以下面的内容在 for-comprehension 中增加了一个级别,并且 doIt
实际上对它传递的数据做了一些事情。其背景是fMaintainers
、fUsersToReview
、doIt
都是作用于一个数据库。
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 的建议,即有时 for-comprehensions 不是正确的工具,这里是地图:
val result:Future[Vector[(String, String)]] =
fMaintainers.flatMap { m ⇒ fUsersToReview.flatMap { u ⇒ doIt(u, m) } }