关于scala:等效扩展(ifEmpty)的有效扩展(RxScala)

Reactive Extensions (RxScala) equivalent of fold ifEmpty

我想知道是否存在与Scala折叠ifEmpty函数等效的集合和选项:

1
fold[B](ifEmpty: => B)(f: (A) => B)

此功能强大,因为它可以在不同的monad类型之间进行转换-例如,以下代码将Option [Person]转换为Observable [Person]:

1
2
3
4
5
case class Person(name: String)

val observable = Option(Person("Paddy")).fold
  { Observable.just[Person]() }  // ifEmpty function
  { p => Observable.just(p) }

我当前的问题是我希望在Reactive Extensions领域中找到类似的东西。我的实际情况更多地要求"空时切换"类型的功能-理想情况是:

1
2
3
4
5
// getFooFromCache returns Observable[Foo] from some cache service
// getFooFromDatabase returns Observable[Foo] from some database service

val sourceObservable = getFooFromCache()
sourceObservable.switchIfEmpty { getFooFromDatabase() }

因此这里的想法是,如果源可观察对象完成并且什么也不发出,则"切换"到另一个可观察对象。如上面所建议的,是一个实际的示例-尝试从缓存中获取某些内容,如果没有返回任何内容,则从数据库中获取它。

我目前实现上述目标的解决方法如下:

1
2
3
4
5
6
7
getFooFromCache()
  .map { Option(_) }
  .orElse { None }
  .flatMap {
    case (Some(foo)) => Observable.just(foo)
    case _ => getFooFromDatabase()
  }

换句话说-将结果package在Option中(以便可以将空结果作为None值发出),然后是带有模式匹配的flatMap。

编辑:如果不存在,这是我将使用的几个扩展功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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()
        }
    }
  }
}

通过上面的操作,我现在可以做到:

1
2
getFooFromCache("item.id")
  .switchIfEmpty { () => getFooFromDatabase("item.id") }


如果您使用的是RxScala 0.24,并且对使用"实验性" API感到满意,则可以

1
import rx.lang.scala.ExperimentalAPIs._

然后做

1
getFooFromCache("item.id").switchIfEmpty(getFooFromDatabase("item.id"))

请注意,该参数已被急切地评估,因此,要获得与您的解决方法相同的效果,您将需要执行

1
getFooFromCache("item.id").switchIfEmpty(Observable.defer(getFooFromDatabase("item.id")))


我认为您需要`orElse [U>:T](默认值:?U):Observable [U]`

`getFooFromCache()。orElse(getFooFromDatabase())`

(此方法是RxScala所基于的RxJava实现中的defaultIfEmpty(T)的[equivalent](http://reactivex.io/rxscala/comparison.html)。