我想知道是否有任何等效的 Scala fold ifEmpty 函数存在于集合和选项中:
fold[B](ifEmpty: => B)(f: (A) => B)
这个函数很强大,因为它可以在不同的 monad 类型之间进行转换——例如,下面将 Option[Person] 转换为 Observable[Person]:
case class Person(name: String)
val observable = Option(Person("Paddy")).fold
{ Observable.just[Person]() } // ifEmpty function
{ p => Observable.just(p) }
我目前的问题是我想要在 Reactive Extensions 领域有类似的东西。我的实际场景更多地需要“如果为空则切换”类型的功能 - 理想情况下:
// getFooFromCache returns Observable[Foo] from some cache service
// getFooFromDatabase returns Observable[Foo] from some database service
val sourceObservable = getFooFromCache()
sourceObservable.switchIfEmpty { getFooFromDatabase() }
所以这里的想法是,如果源 observable 完成并且什么都不发出,那么“切换”到另一个 observable。上面建议的一个实际示例 - 尝试从缓存中获取某些内容,如果没有返回任何内容,则从数据库中获取它。
我目前实现上述目标的解决方法如下:
getFooFromCache()
.map { Option(_) }
.orElse { None }
.flatMap {
case (Some(foo)) => Observable.just(foo)
case _ => getFooFromDatabase()
}
换句话说 - 将结果包装在 Option 中(以便可以将空结果作为 None 值发出),然后将 flatMap 与模式匹配。
编辑:如果不存在,我将使用以下几个扩展函数:
object RxUtils {
implicit class RxUtilExtensions[+T](val observable: Observable[T]) extends AnyVal {
def toOption[U >: T]() : Observable[Option[U]] = {
observable
.map { Option(_) }
.orElse { None }
}
def switchIfEmpty[U >: T](f: () => Observable[U]) : Observable[U] = {
observable.toOption
.flatMap {
case(Some(t)) => Observable.just(t)
case _ => f()
}
}
}
}
有了以上内容,我现在可以做到:
getFooFromCache("item.id")
.switchIfEmpty { () => getFooFromDatabase("item.id") }