Kotlin and RxJava - Why is my Single.zip() not compiling?
我在这里有点疯狂。我正在尝试创建一个
1 2 3 4 5 6 7 8 9 10 11 12 13 | import io.reactivex.Observable import io.reactivex.Single import java.math.BigDecimal fun Observable<BigDecimal>.sum() = reduce { total, next -> total + next } //compile error fun Observable<BigDecimal>.average() = publish().autoConnect(2).let { Single.zip(it.sum().toSingle(), it.count()) { sum, count -> sum / BigDecimal.valueOf(count) } } |
类型推断在rxJava2中通常不起作用。实际上,这不是类型推断问题。 Kotlin通常会生成扩展方法,以用Kotlin功能类型替换SAM,但是由于某种原因,该技术无法用于替代方法。
此处有更多详细信息https://youtrack.jetbrains.com/issue/KT-13609
作为一种选择,您可以尝试指定lambda参数的类型
1 2 3 4 5 6 | fun Observable<BigDecimal>.average() = publish().autoConnect(2).let { Single.zip(it.sum().toSingle(), it.count(), BiFunction { sum: BigDecimal, count: Long -> sum / BigDecimal.valueOf(count) }) } |
由于某种原因类型推断失败,在这种情况下必须可以某种方式推断出多种类型的组合。
您可以使用更传统(不幸的是更冗长)的语法显式指定类型,如下所示:
1 2 3 4 5 6 | fun Observable<BigDecimal>.average() = publish().autoConnect(2).let { Single.zip(it.sum().toSingle(), it.count(), BiFunction<BigDecimal, Long, BigDecimal> { sum, count -> sum / BigDecimal.valueOf(count) }) } |
更新:
在解决类似问题时,我发现这里的实际问题是Kotlin无法推断您要呼叫的
If the Java class has multiple methods taking functional interfaces,
you can choose the one you need to call by using an adapter function
that converts a lambda to a specific SAM type. Those adapter functions
are also generated by the compiler when needed.
因此,事实证明,使用更明确的SAM构造函数可自行解决此问题,并为您提供类型推断(基本上,我以前的回答是使用比实际所需的语法更长的语法):
1 2 3 4 5 6 | fun Observable<BigDecimal>.average(): Single<BigDecimal> = publish().autoConnect(2).let { Single.zip(it.sum().toSingle(), it.count(), BiFunction { sum, count -> sum / BigDecimal.valueOf(count) }) } |
如果类型推断是问题,则您可以做的一件事是使用RxKotlin
1 | implementation"io.reactivex.rxjava2:rxkotlin:$rxKotlinVersion" |
RxKotlin特别提供SAM帮助器,以帮助缓解类型推断问题。
在这种情况下,
1 | Singles.zip(..., ...) |
将能够毫无歧义地正常工作。请注意,我使用的是