Kotlin и RxJava - Почему мой Single.zip() не компилируется?
Я немного сумасшедший. Я пытаюсь создать функцию расширения 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)
}
}
![введите описание изображения здесь]()
Ответы
Ответ 1
Вывод типа в основном не работает для rxJava2. Это не проблема типа вывода. Kotlin обычно генерирует методы расширения, заменяющие SAM функциональными типами kotlin, но по какой-то причине эта техника не работает для переопределенных методов.
Подробнее здесь https://youtrack.jetbrains.com/issue/KT-13609
В качестве опции вы можете попытаться указать типы для аргументов лямбда
fun Observable<BigDecimal>.average() = publish().autoConnect(2).let {
Single.zip(it.sum().toSingle(), it.count(), BiFunction {
sum: BigDecimal, count: Long ->
sum / BigDecimal.valueOf(count)
})
}
Ответ 2
По какой-то причине вывод типов завершается неудачно, в этом контексте должно быть несколько комбинаций типов.
Вы можете явно указать типы с более традиционным (и, к сожалению, более подробным) синтаксисом, например так:
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
перегрузку Single.zip
вы пытаетесь вызвать. Из официальной документации:
Если в классе Java есть несколько методов, принимающих функциональные интерфейсы, вы можете выбрать тот, который вам нужно вызывать, используя функцию адаптера, которая преобразует лямбду в определенный тип 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)
})
}
Ответ 3
Если вывод типа является проблемой, вы можете использовать RxKotlin
implementation "io.reactivex.rxjava2:rxkotlin:$rxKotlinVersion"
RxKotlin специально предоставляет SAM помощники, чтобы помочь смягчить проблемы с выводом типа.
В таком случае,
Singles.zip(..., ...)
сможет работать просто отлично без какой-либо двусмысленности. Обратите внимание, что я использую Singles
а не Single