Kotlin和RxJava - 为什么我的Single.zip()没有编译?

时间:2017-03-06 21:33:12

标签: rx-java kotlin

我在这里有点疯狂。我试图创建一个Observable<BigDecimal>扩展函数(针对RxJava 2.x)来发出平均排放量,但是我使用Single.zip()函数得到了编译错误。有没有人有任何想法我做错了什么?我试图明确我的所有类型,但是没有用......

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)
    }
}

enter image description here

3 个答案:

答案 0 :(得分:33)

类型推断通常不适用于rxJava2。实际上它不是类型推断问题。 Kotlin通常会使用kotlin函数类型生成替换SAM的扩展方法,但由于某种原因,这种技术不适用于重写方法。

此处有更多详情https://youtrack.jetbrains.com/issue/KT-13609

作为一个选项,您可以尝试为lambda参数指定类型

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 :(得分:9)

由于某种原因类型推断失败,必须以某种方式在这种情况下推断出多种类型的组合。

您可以使用更传统(并且遗憾的是更详细)的语法明确指定类型,如下所示:

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无法推断出您试图调用的Single.zip超载。来自official documentation

  

如果Java类有多个方法采用功能接口,   您可以使用适配器功能选择需要呼叫的那个   将lambda转换为特定的SAM类型。那些适配器功能   也是在需要时由编译器生成的。

事实证明,使用更明确的SAM构造函数本身就可以解决这个问题,并为您提供类型推断(基本上,我之前的答案是使用比实际需要更长的语法):

fun Observable<BigDecimal>.average(): Single<BigDecimal> = publish().autoConnect(2).let {
    Single.zip(it.sum().toSingle(), it.count(), BiFunction {
        sum, count ->
        sum / BigDecimal.valueOf(count)
    })
}

答案 2 :(得分:0)

如果类型推断是问题所在,您可以做的一件事是使用RxKotlin

implementation "io.reactivex.rxjava2:rxkotlin:$rxKotlinVersion"

RxKotlin特别提供SAM helpers来帮助缓解类型推断问题。

在这种情况下,

Singles.zip(..., ...)

将能够毫无歧义地正常工作。请注意,我使用的是Singles,而不是Single