您还可以使用函数引用表达式在 Kotlin 中就像 Java 中的方法引用表达式一样。例如,combine
函数参考为KFunction3
在 Kotlin 中如下:
val f: kotlin.reflect.KFunction3<String, Boolean, Int, Double> = this::combine
在java中,方法引用表达式可以分配给任何兼容的 功能接口,但你不能分配一个函数引用表达式任何函数类型,即使它们是兼容的, 例如:
val f:io.reactivex.functions.Function3<String,Boolean,Int,Double> =this::combine
// type mismatch error ---^
事实上,Kotlin 使用SAM 转换转换 lambda/函数引用表达式转化为Java的实现功能接口,这意味着 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();
}
};
Whydid 方法引用表达式在 Java 中可以正常工作,但是使用函数引用表达式Kotlin 失败了?
根据上面的内容,你可以看到有很多重载的地方combineLatest
中的方法rx-java2。例如,以下两个不能使 Kotlin 使用函数引用表达式正确:
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 转换转换 lambda/函数引用表达式到一个Java功能接口,但它不能分配给Java功能接口直接地。
第4个参数combineLatest
Kotlin 中的方法,编译器根本无法推断其类型,因为第四个参数类型可以是io.reactivex.functions.Function3
or ObservableSource
。因为ObservableSource
也是一个Java功能接口.
当你遇见SAM 转换像这样的冲突,你可以使用适配器功能将 lambda 转换为特定的 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/ 之前使用适应函数引用表达式, 例如:
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) }
}
Then你可以使用函数引用表达式如下,例如:
Observable.combineLatest(
strings(),
booleans(),
integers(),
// v--- convert KFunction3 to RxFunction3 explicitly
this::combine.toFunction3()
)