使用泛型的 Kotlin 构造函数参考

Kotlin constructor reference with generics

我在 (Rx) 中有此代码Java:

Observable.fromArray(1, 2, 3)
    .flatMap(this::intToBooleanObservable, Pair::new)
    .....

我希望相应的 Kotlin 代码如下所示:

Observable.fromArray(1, 2, 3)
    .flatMap(::intToBooleanObservable, ::Pair)
    .....

但是编译器无法推断 Pair 的泛型类型,所以我现在能做的最好的是:

.flatMap(::intToBooleanObservable, { a, b -> a to b })

这并不像我希望的那样简洁。

有没有办法在不声明变量 ab 的情况下实现这一点?

同样的问题。其他一些解决方法(按照我使用它们的顺序),您可能会喜欢其中之一。

1) 编写自己的运算符:

fun <T, U> Single<T>.flatMapPair(func: (T) -> Single<U>) : Single<Pair<T, U>> {
    return this.flatMap { t -> func.invoke(t).map { u -> t to u } }
}

2) 将包装移动到条件 Observable(这里是 intToBooleanObservable),将结果作为 Pair 或更明确的自定义类型(密封 class 与 2 个孩子,如成功和失败)返回。这会启用更明确的代码:

 when(it) {
   is Success -> ...
   is Failure -> ...
}

3) 根据 intToBooleanObservable 结果,您现在有 2 种不同的场景(我想)。通常一个是一种failure/denial,快速解决。为此,编写一个具有副作用的过滤器,其中谓词是一个 Observable,从而避免了这个问题:

fun <T> Observable<T>.filterSingle(predicate: (T) -> Single<Boolean>, rejectionFunction: (T) -> Unit): Observable<T> = ... //filter with the given predicate, and call rejectionFunction if item doesn't pass

4) 最后一种方法仅适用于布尔结果。如果我对 failure/refusal 背后的原因感兴趣并给出有意义的信息怎么办?为了同构代码,我放弃了这个运算符。受其他函数式语言的启发,我定义了一个 Either 类型并定义了通用的 Either+RxJava 操作符; mapRight、flatMapRight 和更重要的 dropLeft。 dropLeft 就像是 filterSingle 的推广。

inline fun <L, R> Observable<Either<L, R>>.dropLeft(crossinline sideEffect: (L) -> Unit): Observable<R> = this.lift { downObserver ->
    object: Observer<Either<L, R>> {
        override fun onError(throwable: Throwable?) = downObserver.onError(throwable)

        override fun onSubscribe(disposable: Disposable?) = downObserver.onSubscribe(disposable)

        override fun onComplete() = downObserver.onComplete()

        override fun onNext(either: Either<L, R>) = when (either) {
            is Right -> downObserver.onNext(either.value)
            is Left -> sideEffect(either.value)
        }
    }
}

希望对您有所帮助。