我有一系列参数。对于每个参数,我必须执行数据库查询,这可能会也可能不会返回结果。简单来说,我需要在第一个结果非空后停止。当然,我想避免做不必要的电话。需要注意的是 - 我需要将此操作作为另一个未来 - 或任何“最具反应性”的方法。 说到代码:
for each emp no-lock by emp.FirstName desc by emp.LastName :
我知道我可以将整个函数包装在另一个//that what I have
def dbQuery(p:Param): Future[Option[Result]] = {}
//my list of params
val input = Seq(p1,p2,p3)
//that what I need to implements
def getFirstNonEmpty(params:Seq[Param]): Future[Option[Result]]
中并按顺序执行代码(Await?Brrr ...),但这不是最干净的解决方案。
我可以以某种方式创建懒惰的初始化期货集合,如
Future
我相信这是可能的!
答案 0 :(得分:1)
你怎么看待这样的事情?
def getFirstNonEmpty(params: Seq[Param]): Future[Option[Result]] = {
params.foldLeft(Future.successful(Option.empty[Result])) { (accuFtrOpt, param) =>
accuFtrOpt.flatMap {
case None => dbQuery(param)
case result => Future.successful(result)
}
}
}
答案 1 :(得分:0)
这可能有点矫枉过正,但如果您愿意使用scalaz,我们可以使用OptionT
和foldMap
执行此操作。
使用OptionT
,我们将Future
和Option
组合成一个结构。我们可以使用Future
获取带有非空结果的两个OptionT.orElse
中的第一个。
import scalaz._, Scalaz._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
val someF: Future[Option[Int]] = Future.successful(Some(1))
val noneF: Future[Option[Int]] = Future.successful(None)
val first = OptionT(noneF) orElse OptionT(someF)
first.run // Future[Option[Int]] = Success(Some(1))
我们现在可以从标准库中Future
获取List
的第一个非空reduce
(但这将运行所有Future
s):< / p>
List(noneF, noneF, someF).map(OptionT.apply).reduce(_ orElse _).run
但是对于List
(或其他集合),我们无法确定至少有一个元素,因此我们需要使用fold
并传递起始值。 Scalaz可以使用Monoid
为我们完成这项工作。我们将使用的Monoid[OptionT[Future, Int]]
将提供起始值,并将Future
与上面使用的orElse
合并。
type Param = Int
type Result = Int
type FutureO[x] = OptionT[Future, x]
def query(p: Param): Future[Option[Result]] =
Future.successful{ println(p); if (p > 2) Some(p) else None }
def getFirstNonEmpty(params: List[Param]): Future[Option[Result]] = {
implicit val monoid = PlusEmpty[FutureO].monoid[Result]
params.foldMap(p => OptionT(query(p))).run
}
val result = getFirstNonEmpty(List(1,2,3,4))
// prints 1, 2, 3
result.foreach(println) // Some(3)
答案 2 :(得分:0)
这是一个古老的问题,但是如果有人来寻找答案,这是我的看法。我针对一个用例解决了该问题,该用例要求我依次循环访问有限数量的期货,并在第一个期货返回结果时停止。
我的用例不需要一个库,轻量级的递归和模式匹配就足够了。尽管这里的问题与期货序列没有相同的问题,但是遍历一系列参数将是相似的。
这是基于递归的伪代码。
我尚未编译此文件,请修复要匹配/返回的类型。
def getFirstNonEmpty(params: Seq[Param]): Future[Option[Result]] = {
if (params.isEmpty) {
Future.successful(None)
} else {
val head = params.head
dbQuery(head) match {
case Some(v) => Future.successful(Some(v))
case None => getFirstNonEmpty(params.tail)
}
}
}