使用函数引用重写Kotlin中的Java代码会发生SAMtypes冲突
我有一个示例Java代码使用方法引用,我想重写到Kotlin。 Java版本使用方法参考,解决方案简短明了。 但另一方面,我不能在Kotlin中使用方法引用。 我设法编写的唯一版本是下面介绍的一个。 看起来像Function3 { s: String, b: Boolean, i: Int -> combine(s, b, i) }
可以用更简洁的方式编写(如果可能的话,方法引用将是完美的)。
我是Kotlin新手,所以我会感激任何线索。
Java的
import io.reactivex.Observable; public class TestJava { Observable strings() { return Observable.just("test"); } Observable booleans() { return Observable.just(true); } Observable 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 { return Observable.just("test") } fun booleans(): Observable { return Observable.just(true) } fun integers(): Observable { 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 } }
编辑
以下Kotlin中的方法引用给出了一个错误。
fun test() { Observable.combineLatest(strings(), booleans(), integers(), this::combine) } fun test() { Observable.combineLatest(strings(), booleans(), integers(), TestKotlin::combine) }
下面的函数都不能用所提供的参数调用:@CheckReturnValue @SchedulerSupport public final fun combineLatest(p0:((Observer) – > Unit)!, p1:((Observer) – > Unit)!, p2:(观察者) – >单位)!,p3:((???,???) – >))!):可观察<(??? ..))! 定义在io.reactivex.Observable @CheckReturnValue @SchedulerSupport public open fun combineLatest(p0:ObservableSource!,p1:ObservableSource!,p2:ObservableSource!,p3:io.reactivex.functions.Function3!):Observable ! 定义在io.reactivex.Observable @CheckReturnValue @SchedulerSupport public open fun combineLatest(p0:Function !, out(??? .. ???)> !, p1:Int,vararg p2:ObservableSource!):Observable ! 在io.reactivex.Observable中定义
编辑2
RxKotlin解决了答案中提到的问题。
import io.reactivex.rxkotlin.Observables class TestKotlin { fun test() { Observables.combineLatest(strings(), booleans(), integers(), this::combine) } }
您也可以像使用Java中的方法引用expression式一样在Kotlin中使用函数引用expression式 。 例如Kotlin中KFunction3
的combine
函数参考如下:
val f: kotlin.reflect.KFunction3 = this::combine
在java中,方法引用expression式可以分配给任何兼容的 function接口 ,但是即使它们是兼容的 ,也不能将函数引用expression式分配给任何函数types,例如:
val f:io.reactivex.functions.Function3 =this::combine // type mismatch error ---^
实际上,Kotlin使用SAM转换将lambda / Function Reference Expression转换为Java Functional Interface的实现,这意味着Kotlin的function如下:
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(); } };
为什么方法引用expression式可以在Java中正常工作,但是在Kotlin中使用函数引用expression式失败?
基于上面,你可以看到在rx-java2中有很多重载的combineLatest
方法。 例如,以下两个不能使Kotlin正确使用函数引用expression式 :
combineLatest( ObservableSource, ObservableSource , ObservableSource , Function3 ) combineLatest( ObservableSource , ObservableSource , ObservableSource , ObservableSource , Function4 )
正如我所说的使用SAM转换的 Kotlin将lambda / Function引用expression式转换为Java Functional Interface ,但不能直接分配给Java Functional Interface 。
由于第四个参数types可以是io.reactivex.functions.Function3
或ObservableSource
,所以在Kotlin中combineLatest
方法的第四个参数,编译器根本无法推断它的types。 因为ObservableSource
也是一个Java function接口 。
当像这样遇到SAM转换冲突时,可以使用将lambda转换为特定SAMtypes的适配器函数 ,例如:
typealias RxFunction3 = io.reactivex.functions.Function3 val f: RxFunction3 = RxFunction3{ s, b, i-> 1.0}
所以你必须在使用lambda / Function Reference Expression之前使用适配,例如:
typealias RxFunction3 = io.reactivex.functions.Function3 fun KFunction3.toFunction3(): RxFunction3 { return RxFunction3 { t1, t2, t3 -> invoke(t1, t2, t3) } }
然后你可以使用下面的函数参考expression式 ,例如:
Observable.combineLatest( strings(), booleans(), integers(), // v--- convert KFunction3 to RxFunction3 explicitly this::combine.toFunction3() )