這可能是矯枉過正,但如果你是開放的使用scalaz我們可以使用OptionT
和foldMap
做到這一點。
With OptionT
我們將Future
和Option
合併成一個結構。我們可以使用OptionT.orElse
獲得兩個Future
s中的第一個,結果爲非空。
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))
我們現在可以用reduce
標準庫中得到一個List
的第一個非空Future
(然而,這將運行所有Future
S):
List(noneF, noneF, someF).map(OptionT.apply).reduce(_ orElse _).run
但是隨着List
(或其他收集)我們不能確定至少有一個元素,所以我們需要使用fold
並傳遞一個起始值。斯卡拉茲可以通過使用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)
第一件事來我的腦海:'params.toStream.map {P =>的DBQuery(P)} {.dropWhile F => f.value.isEmpty} .head' –
@VictorMoroz引述'未來.value ScalaDoc:*如果未來未完成,返回值將爲None *。我認爲你不想因爲未完成而跳過未來。它還會返回一個'Result'而不是'Future [Option [Result]]'。 –
參數序列是否有序?換句話說,如果'p1'和'p2'都會產生一個非空結果,那麼使用p1結果而不是'p2'結果很重要嗎?如果不是,您可以考慮從Futures的第一個(即最快)返回非空的集合中啓動所有參數並獲取。 – jwvh