web-dev-qa-db-fra.com

Kotlin et RxJava - Pourquoi mon Single.Zip () ne compile-t-il pas?

Je deviens un peu fou ici. J'essaie de créer une fonction d'extension Observable<BigDecimal> (Contre RxJava 2.x) pour émettre la moyenne des émissions, mais j'obtiens une erreur de compilation avec la fonction Single.Zip(). Quelqu'un at-il une idée de ce que je fais mal? J'ai aussi essayé d'être explicite avec tous mes types et ça n'a pas marché ...

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

22
tmn

L'inférence de type ne fonctionne généralement pas pour rxJava2. Ce n'est pas un problème d'inférence de type en fait. Kotlin génère généralement des méthodes d'extension qui remplacent SAM par des types fonctionnels kotlin, mais cette technique ne fonctionne pas pour les méthodes remplacées pour une raison quelconque.

Plus de détails ici https://youtrack.jetbrains.com/issue/KT-13609

En option, vous pouvez essayer de spécifier des types pour les arguments 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)
    })
}
37
Stepango

L'inférence de type échoue pour une raison quelconque, il doit y avoir en quelque sorte plusieurs combinaisons de types qui pourraient être déduites dans ce contexte.

Vous pouvez spécifier les types explicitement avec une syntaxe plus traditionnelle (et malheureusement plus verbeuse), comme ceci:

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

Mise à jour:

Je viens de découvrir en travaillant sur un problème similaire que le vrai problème ici est que Kotlin n'est pas en mesure de déduire quel Single.Zip surcharge que vous essayez d'appeler. De la documentation officielle :

Si la classe Java possède plusieurs méthodes prenant des interfaces fonctionnelles, vous pouvez choisir celle que vous devez appeler en utilisant une fonction d'adaptateur qui convertit un lambda en un type SAM spécifique. Ces fonctions d'adaptateur sont également générées par le compilateur en cas de besoin.

Il s'avère donc que l'utilisation du constructeur SAM plus explicite résout ce problème en soi et vous donne une inférence de type (en gros, ma réponse précédente utilisait une syntaxe plus longue que celle réellement requise):

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

Si l'inférence de type est le problème, une chose que vous pouvez faire est d'utiliser RxKotlin

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

RxKotlin fournit spécifiquement assistants SAM pour aider à atténuer les problèmes liés aux problèmes d'inférence de type.

Dans quel cas,

Singles.Zip(..., ...)

serait en mesure de fonctionner très bien sans aucune ambiguïté. Remarquez que j'utilise Singles et non Single

0
William Reed