Intereting Posts
Создание нескольких конструкторов Kotlin, которые не имеют общих параметров Использовать значение аргумента по умолчанию в вызове функции Kotlin Ошибка кинжала 2: зависимость "не может быть предоставлена ​​без конструктора @Inject" ошибка в аннотациях kotlin? Robolectric test и LiveData Обновление содержимого субтитров MediaBrowserService IlegalStateException, где выбрасывается при попытке получить значения из экземпляра RoomDatabase В Kotlin Как я могу преобразовать Int? к Int Единичный тест на функцию расширения Kotlin на Android SDK Classes Не следует ли нам назвать функцию, аналогичную существующему классу в Котлине? Зачем? Хранить данные в BEAN (Spring Boot REST) Добавить сгенерированное значение в объект RealmObject Соглашение об именовании котинов для логических методов возврата Как изменить цвет фона карты, когда он выбран? Могу ли я добавить возврат, когда я использую операцию Элвиса в Котлине?

Перепишите Java-код в Kotlin, используя функцию Reference, возникает конфликт типов SAM

У меня есть пример кода Java, использующего ссылку на метод, которую я хочу переписать в Kotlin. Java-версия использует ссылку на метод, решение короткое и понятное. Но, с другой стороны, я не могу использовать ссылку на метод в Котлине. Единственная версия, которую мне удалось написать, – это одна из представленных ниже. Кажется, что Function3 { s: String, b: Boolean, i: Int -> combine(s, b, i) } может быть написано более чистым способом (если возможно, ссылка на метод была бы идеальной).

Я новичок в Котлине, поэтому буду благодарен за любые подсказки.

Ява

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

Котлин

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

РЕДАКТИРОВАТЬ

Следующие рекомендации метода в Котлин дают ошибку.

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

Ни одна из следующих функций не может быть вызвана с предоставленными аргументами: @CheckReturnValue @SchedulerSupport public final fun combLatest (p0: ((Observer) -> Unit) !, p1: ((Observer) -> Unit) !, p2: (( Observer) -> Unit) !, p3: ((???, ???, ???) -> ???)!): Наблюдаемый <(??? .. ???)>! определяется в io.reactivex.Observable @CheckReturnValue @SchedulerSupport public open fun combLatest (p0: ObservableSource !, p1: ObservableSource !, p2: ObservableSource !, p3: io.reactivex.functions.Function3!): Observable <(???. . ???)>! определяемый в io.reactivex.Observable @CheckReturnValue @SchedulerSupport public open fun combLatest (p0: Function !, out (??? .. ???)> !, p1: Int, vararg p2: ObservableSource!): Observable <(? ?? .. ???)>! определен в io.reactivex.Observable

EDIT 2

RxKotlin решает проблему, упомянутую в ответе.

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

Вы также можете использовать функцию Reference Expression в Kotlin, как и выражение Reference Reference в Java. например, ссылку на функцию combine как KFunction3 в Котлин, как KFunction3 ниже:

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

В java метод Reference Expression может назначать любой совместимый функциональный интерфейс , но вы не можете назначать выражение функции Reference для любых типов функций, даже если они совместимы , например:

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

В самом деле, Kotlin использует SAM Conversions для преобразования lambda / Function Reference Expression в реализацию Java Functional Interface , что означает, что Kotlin делает что-то вроде ниже:

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

Почему метод Reference Expression отлично работает на Java, но с использованием функции Reference Expression в Kotlin не удалось?

Основываясь на выше, и вы можете увидеть, что в rx-java2 есть много перегруженных методов combineLatest . например, следующие два не могут заставить Kotlin правильно использовать выражение функции Reference :

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

Как я уже сказал, Kotlin использует SAM Conversions для преобразования lambda / Function Reference Expression в Java Functional Interface , но не может напрямую назначать Java- интерфейс .

4-й параметр метода combineLatest в Котлине, компилятор вообще не может вывести его тип, поскольку 4-й тип параметра может быть io.reactivex.functions.Function3 или ObservableSource . потому что ObservableSource также является функциональным интерфейсом Java.

Когда вы встречаете конфликт конверсии SAM, как это, вы можете использовать функцию адаптера, которая преобразует лямбда в конкретный тип SAM, например:

 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} 

Поэтому вы должны использовать адаптацию перед использованием lambda / 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) } } 

Затем вы можете использовать функцию Reference Expression, как показано ниже:

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