2017-07-15 1 views
4

Ich habe einen Beispiel-Java-Code mit Methodenreferenz, die ich auf Kotlin umschreiben möchte. Java-Version verwendet Methodenreferenz, Lösung ist kurz und klar. Aber auf der anderen Seite kann ich in Kotlin keine Methodenreferenz verwenden. Die einzige Version, die ich geschrieben habe, ist eine, die unten vorgestellt wird. Es scheint so, als ob Function3 { s: String, b: Boolean, i: Int -> combine(s, b, i) } sauberer geschrieben werden könnte (wenn möglich wäre die Methodenreferenz perfekt).Rewrite Java-Code in Kotlin mit Funktionsreferenz auftritt SAM-Typen Konflikt

Ich bin neu in Kotlin, also werde ich für Hinweise dankbar sein.

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

EDIT

Nach Methode Referenzen in Kotlin gibt einen Fehler.

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

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

Keiner der folgenden Funktionen können mit den Argumenten aufgerufen werden geliefert: @CheckReturnValue @SchedulerSupport public final Spaß combineLatest (p0: ((Observer) -> Unit) !, p1: ((Observer) -> Einheit!!, P2: ((Beobachter) -> Einheit) !, p3: ((???, ???, ???) -> ???)!): Observable < (?? ? .. ???)>! in io.reactivex.Observable definiert @CheckReturnValue @SchedulerSupport Öffentlichkeit zugänglich Spaß combineLatest (p0: ObservableSource !, p1: ObservableSource !, p2: ObservableSource !, p3: io.reactivex.functions.Function3!): beobachtbare < (? ?? .. ???)>! in io.reactivex.Observable definiert @CheckReturnValue @SchedulerSupport Öffentlichkeit zugänglich Spaß combineLatest (p0: Funktion !, aus (??? .. ???)> !, p1: Int, Vararg p2: ObservableSource!): beobachtbare < (??? .. ???)>! definiert in io.reactivex.Observable

EDIT 2

RxKotlin löst Problem in Antwort erwähnt.

import io.reactivex.rxkotlin.Observables 

class TestKotlin { 

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

} 
+0

Erstens, ich bin nicht der Wermutstropfen. Hast du es versucht? –

+0

_ "Ich kann in Kotlin keine Methodenreferenz verwenden" _ Warum nicht? –

+0

@ Holi-Java natürlich versuchte ich –

Antwort

5

Sie können auch Function Reference Expression in Kotlin mit wie als Ausdruck Methode Referenz in Java.die combine Funktionsreferenz als KFunction3 in Kotlin zum Beispiel wie folgt:

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

in Java, Expression-Methode Es kann auf jeden kompatibelFunctional Interface, weist aber man kann nicht ein Function Reference Expression auf alle Funktionstypen selbst zuweisen, wenn sie sind kompatibel, zum Beispiel:

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

Tatsächlich Kotlin mit SAM Conversions Lambda/Function Reference Expression in eine Implementierung konvertieren von Java Functional Interface, was bedeutet, Kotlin etwas tut, wie wie folgt:

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

Warum tat Referenzmethode Expression kann fein in Java funktioniert, aber mit Function Reference Expression ist fehlgeschlagen in Kotlin?

Basis auf dem oben genannten, und Sie können sehen, es gibt viele überladenen combineLatest Methoden in . können beispielsweise die folgend beide nicht Kotlin Function Reference Expression richtig mit machen:

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

Wie gesagt Kotlin SAM Conversions mit einem Lambda/Function Reference Expression zu einem Java Functional Interface, konvertieren, aber es Functional Interface direkt mit einem Java nicht zuordnen kann .

Der vierte Parameter der combineLatest Methode in Kotlin, der Compiler kann seinen Typ überhaupt nicht ableiten, da der 4. Parametertyp io.reactivex.functions.Function3 oder ObservableSource sein kann. weil ObservableSource auch ein Java Functional Interface ist.

Wenn Sie treffen SAM Conversion Konflikte wie wie diese, können Sie eine Adapterfunktion verwenden, die eine Lambda zu einem bestimmten SAM-Typ umwandelt, zum Beispiel:

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} 

So müssen Sie eine Anpassung mit vor Lambda mit zum Beispiel/Function Reference Expression,:

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

Dann Sie Function Reference Expression wie unten, zum Beispiel unter Verwendung kann:

Observable.combineLatest(
     strings(), 
     booleans(), 
     integers(), 
     //    v--- convert KFunction3 to RxFunction3 explicitly 
     this::combine.toFunction3() 
) 
+0

Vielen Dank für diese Antwort :). Bis heute war mir nicht bewusst, dass ein solches Problem existiert. Gerade gefunden RxKotlin https://github.com/ReactiveX/RxKotlin, die dieses Problem löst. –

+0

@AleksanderMielczarek Überhaupt nicht. Ich finde das Problem gerade jetzt in rx-java2. Ich habe nie [tag: rx-java2], :) benutzt. –

+0

Verwenden Sie 'import io.reactivex.rxkotlin.Observables' anstelle einer regulären Observablen. Die Klassenbeschreibung lautet "SAM-Adapter zur Unterstützung der Kotlin-Lambda-Unterstützung" – feresr

1

@ Holi-java Antwort groß ist, erklärt es, warum dieses Problem auftritt, hier habe ich für diejenigen, die eine schnelle Lösung bin Bereitstellung, die gerade das Problem loswerden wollen:

In rxJava2 Verwendung io.reactivex.rxkotlin.Observables statt io.reactivex.Observable zu Ihrem Observablen kombinieren:

Observables.combineLatest(src1, src2, ::yourFunction)

Dies sollte aus dem Kasten heraus arbeiten.