Reescriba el código de Java en Kotlin utilizando la reference de function.

Tengo un código de Java de ejemplo que utiliza la reference de método que quiero reescribir a Kotlin. La versión de Java usa la reference de método, la solución es corta y clara. Pero, por otro lado, no puedo usar la reference de método en Kotlin. La única versión que he logrado escribir es la que se presenta a continuación. Parece que Function3 { s: String, b: Boolean, i: Int -> combine(s, b, i) } podría escribirse de una manera más limpia (si es posible, la reference del método sería perfecta).

Soy nuevo en Kotlin, así que agradeceré cualquier pista.

Java

 import io.reactivex.Observable; public class TestJava { Observable<String> strings() { return Observable.just("test"); } Observable<Boolean> booleans() { return Observable.just(true); } Observable<Integer> integers() { return Observable.just(1); } void test() { Observable.combineLatest(strings(), booleans(), integers(), this::combine); } double combine(String s, boolean b, int i) { return 1.0; } } 

Kotlin

 import io.reactivex.Observable import io.reactivex.functions.Function3 class TestKotlin { fun strings(): Observable<String> { return Observable.just("test") } fun booleans(): Observable<Boolean> { return Observable.just(true) } fun integers(): Observable<Int> { return Observable.just(1) } fun test() { Observable.combineLatest(strings(), booleans(), integers(), Function3 { s: String, b: Boolean, i: Int -> combine(s, b, i) }) } fun combine(s: String, b: Boolean, i: Int): Double { return 1.0 } } 

EDITAR

El siguiente método de references en Kotlin da un error.

 fun test() { Observable.combineLatest(strings(), booleans(), integers(), this::combine) } fun test() { Observable.combineLatest(strings(), booleans(), integers(), TestKotlin::combine) } 

No se puede invocar ninguna de las siguientes funciones con los arguments suministrados: @CheckReturnValue @SchedulerSupport público final fundado combine Latest (p0: ((Observer) -> Unit) !, p1: ((Observer) -> Unit) !, p2: (( Observer) -> Unidad) !, p3: ((???, ???, ???) -> ???)!): Observable <(??? .. ???)>! definido en io.reactivex.Observable @CheckReturnValue @SchedulerSupport public open funciona combine-latest (p0: ¡ObservableSource !, p1: ObservableSource !, p2: ObservableSource !, p3: io.reactivex.functions.Function3!): Observable <(???. . ???)>! definido en io.reactivex.Observable @CheckReturnValue @SchedulerSupport abierto público fundado combine Latest (p0: Function !, out (??? .. ???)> !, p1: Int, vararg p2: ObservableSource!): Observable <(? ?? .. ???)>! definido en io.reactivex.Observable

EDIT 2

RxKotlin resuelve el problema mencionado en la respuesta.

 import io.reactivex.rxkotlin.Observables class TestKotlin { fun test() { Observables.combineLatest(strings(), booleans(), integers(), this::combine) } } 

También puede usar Expresión de reference de function en Kotlin al igual que Expresión de reference de método en Java. por ejemplo, la reference de function combine como KFunction3 en Kotlin como se muestra a continuación:

 val f: kotlin.reflect.KFunction3<String, Boolean, Int, Double> = this::combine 

En Java, Method Reference Expression se puede asignar a cualquier interfaz funcional compatible , pero no se puede asignar una expresión de reference de function a ningún tipo de function, incluso si son compatibles , por ejemplo:

 val f:io.reactivex.functions.Function3<String,Boolean,Int,Double> =this::combine // type mismatch error ---^ 

De hecho, Kotlin usa las Conversiones SAM para convertir lambda / Function Reference Expression en una implementación de Java Functional Interface , lo que significa que Kotlin hace algo como lo siguiente:

 fun test() = TODO() val exector:Executor = TODO() exector.execute(::test) //::test compile to java code as below: Runnable task = new Runnable(){ public void run(){ test(); } }; 

¿ Por qué Method Reference Expression puede funcionar bien en Java, pero al usar Function Reference Expression falla en Kotlin?

Basa en lo anterior, y puedes ver que hay muchos methods combineLatest en rx-java2 . por ejemplo, los siguientes dos no pueden hacer que Kotlin use la Expresión de reference de function correctamente:

 combineLatest( ObservableSource<out T1>, ObservableSource<out T2>, ObservableSource<out T3>, Function3<T1, T2, T3, out R> ) combineLatest( ObservableSource<out T1>, ObservableSource<out T2>, ObservableSource<out T3>, ObservableSource<out T4>, Function4<T1, T2, T3, T4, out R> ) 

Como dije, Kotlin usa las Conversiones SAM para convertir una expresión de reference de function / lambda en una interfaz funcional de Java, pero no puede asignar una interfaz funcional de Java directamente.

El 4 ° parámetro del método combineLatest en Kotlin, el comstackdor no puede inferir su tipo en absoluto, ya que el 4 ° tipo de parámetro puede ser io.reactivex.functions.Function3 u ObservableSource . porque ObservableSource es también una interfaz funcional de Java.

Cuando se encuentra con un conflicto de conversión de SAM como este, puede usar una function de adaptador que convierta un lambda a un tipo de SAM específico, por ejemplo:

 typealias RxFunction3<T1, T2, T3, R> = io.reactivex.functions.Function3<T1,T2,T3,R> val f: RxFunction3<String, Boolean, Int, Double> = RxFunction3{ s, b, i-> 1.0} 

Por lo tanto, debe usar una adaptación antes de usar lambda / Function Reference Expression , por ejemplo:

 typealias RxFunction3<T1, T2, T3, R> = io.reactivex.functions.Function3<T1,T2,T3,R> fun <T1,T2,T3,R> KFunction3<T1,T2,T3,R>.toFunction3(): RxFunction3<T1, T2,T3,R> { return RxFunction3 { t1, t2, t3 -> invoke(t1, t2, t3) } } 

Luego puede usar Expresión de reference de function como se muestra a continuación, por ejemplo:

 Observable.combineLatest( strings(), booleans(), integers(), // v--- convert KFunction3 to RxFunction3 explicitly this::combine.toFunction3() ) 
  • EXCEPCIÓN FATAL: RxCachedThreadScheduler-1 cuando el gatillo se deshace. ¿Por qué?
  • Invoque RxJava2 cancelable / desechable del hilo correcto
  • Cómo hacer un event handling errores en rxjava2 en android
  • Completable.andThen resultados en "other is null"
  • Single.zip completando antes de Success
  • RxJava2 cómo separar diferentes implementaciones de emisor observable
  • ¿Hay alguna manera de cambiar mi método a la stream Observable que será una cadena de modificadores?
  • RxJava Debounce onNext ()
  • Room - SELECT query, get o default
  • ¿Cómo iterar sobre Single <List> y asignar a otra list?
  • RxJava 1.x .zip () no funciona en RxJava 2.0