Future[Option[T]]:如果定义了 Option,则保留 future 否则回退到另一个 future

Future[Option[T]]: Keep future if Option is defined otherwise fallback to another future

我有这个 val cacheElement:Future[Option[T]],如果 Option 是一个 Some,我想要的结果是保持这个未来,或者如果未来是 None。使用模式匹配看起来像这样:

val cacheElement:Future[Option[T]] = cache.get[T](cacheKey)

for {
    opt <- cacheElement flatMap {
        case Some(cached) => Future { Some(cached) } 
        case None => createFallback(args)
           }
} yield { opt match {
        case Some(_) => //do something
        case None => // Do something else   
    }
}


def createFallback[T](args:T):Future[Option[T]] = ???-

我怎样才能以更优雅和简洁的方式做到这一点? Future { Some(cached) } 的这种重复在我看来非常冗长

import scala.concurrent.Future
import scala.concurrent.Await
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

type T = String

val cacheElement: Future[Option[T]] = Future.successful(Some("asd"))
val failElement: Future[Option[T]] = Future.successful(None)

def createFallback: Future[T] = Future.successful("fallback")

val s = cacheElement.flatMap(_.fold(createFallback)(Future.successful))
val f = failElement.flatMap(_.fold(createFallback)(Future.successful))

Await.result(s, 1.second)
//res0: T = asd
Await.result(f, 1.second)
//res1: T = fallback

OptionT 来自 cats 的 monad 转换器提供了 orElse 像这样的语法

OptionT(cacheElement) orElse OptionT(createFallback(args))

例如

import cats.data.OptionT
import cats.implicits._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

object OptionTExample extends App {
  val f: Future[Option[Int]] = Future(None)
  def fallback: Future[Option[Int]] = Future(Some(-1))
  val v = OptionT(f) orElse OptionT(fallback)
  v.value.map(println)
}

产出

Some(-1)