简体   繁体   English

使用函数引用在Kotlin中重写Java代码发生SAM类型冲突

[英]Rewrite Java code in Kotlin using Function Reference occurs SAM types conflict

I have an example Java code using method reference that I want to rewrite to Kotlin. 我有一个示例Java代码使用方法引用,我想重写为Kotlin。 Java version is using method reference, solution is short and clear. Java版本使用方法参考,解决方案简短明了。 But on the other hand I cannot use method reference in Kotlin. 但另一方面,我不能在Kotlin中使用方法参考。 The only version that I've managed to write is one presented below. 我设法编写的唯一版本如下所示。 It seems like Function3 { s: String, b: Boolean, i: Int -> combine(s, b, i) } could be written in cleaner way (if possible method reference would be perfect). 看起来像Function3 { s: String, b: Boolean, i: Int -> combine(s, b, i) }可以用更干净的方式编写(如果可能的方法参考将是完美的)。

I'm new to Kotlin so I'll be grateful for any clues. 我是Kotlin的新手,所以我会感激任何线索。

Java 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 编辑

Following method references in Kotlin gives an error. 以下Kotlin中的方法引用给出了错误。

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

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

None of the following functions can be called with the arguments supplied: @CheckReturnValue @SchedulerSupport public final fun combineLatest(p0: ((Observer) -> Unit)!, p1: ((Observer) -> Unit)!, p2: ((Observer) -> Unit)!, p3: ((???, ???, ???) -> ???)!): Observable<(???..???)>! 使用提供的参数不能调用以下函数:@CheckReturnValue @SchedulerSupport public final fun combineLatest(p0:((Observer) - > Unit)!,p1:((Observer) - > Unit)!,p2:((观察者) - >单位)!,p3:((???,???,???) - > ???)!):可观察<(??? ???)>! defined in 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:ObservableSource!,p1:ObservableSource!,p2:ObservableSource!,p3:io.reactivex.functions.Function3!):Observable <(???。 ???)>! defined in io.reactivex.Observable @CheckReturnValue @SchedulerSupport public open fun combineLatest(p0: Function!, out (???..???)>!, p1: Int, vararg p2: ObservableSource!): Observable<(???..???)>! 在io.reactivex.Observable中定义@CheckReturnValue @SchedulerSupport public open fun combineLatest(p0:Function!,out(??? .. ???)>!,p1:Int,vararg p2:ObservableSource!):Observable <(? ?? .. ???)>! defined in io.reactivex.Observable 在io.reactivex.Observable中定义

EDIT 2 编辑2

RxKotlin solves issue mentioned in answer. RxKotlin解决了答案中提到的问题。

import io.reactivex.rxkotlin.Observables

class TestKotlin {

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

}

You can also using Function Reference Expression in Kotlin just like as Method Reference Expression in Java. 您也可以在Kotlin中使用函数引用表达式 ,就像Java中的方法引用表达式一样。 for example, the combine function reference as KFunction3 in Kotlin as below: 例如,Kotlin中的combine函数引用为KFunction3 ,如下所示:

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

In java, Method Reference Expression can assign to any compatible Functional Interface , but you can't assign a Function Reference Expression to any Function types even if they are compatible , for example: 在java中,方法引用表达式可以分配给任何兼容的 功能接口 ,但是您不能将功能引用表达式分配给任何功能类型,即使它们是兼容的 ,例如:

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

Indeed, Kotlin using SAM Conversions to convert lambda/ Function Reference Expression into an implementation of Java Functional Interface , which means Kotlin does something like as below: 实际上,Kotlin使用SAM转换将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();
   }
};

Why did Method Reference Expression can works fine in Java, but using Function Reference Expression is failed in Kotlin? 为什么方法参考表达式在Java中可以正常工作,但在Kotlin中使用函数参考表达式失败了?

Base on the above, and you can see there are many overloaded combineLatest methods in . 基于上面的内容,您可以看到有许多重载的combineLatest方法。 for example, the following two can't make Kotlin using Function Reference Expression correctly: 例如,以下两个不能正确使用函数引用表达式 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>
)

As I said Kotlin using SAM Conversions to convert a lambda/ Function Reference Expression to a Java Functional Interface , but it can't assign to a Java Functional Interface directly. 正如我所说,Kotlin使用SAM转换将lambda / 函数引用表达式转换为Java 功能接口 ,但它不能直接分配给Java 功能接口

The 4th parameter of the combineLatest method in Kotlin, the compiler can't infer its type at all, since the 4th parameter type can be io.reactivex.functions.Function3 or ObservableSource . Kotlin中combineLatest方法的第4个参数,编译器根本无法推断它的类型,因为第4个参数类型可以是io.reactivex.functions.Function3ObservableSource because ObservableSource is also a Java Functional Interface . 因为ObservableSource也是一个Java 功能接口

When you meet SAM Conversion conflict like as this, you can using an adapter function that converts a lambda to a specific SAM type, for example: 当您遇到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}

So you must using an adaption before using lambda/ Function Reference Expression , for example: 因此,在使用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) }
}

Then you can using Function Reference Expression as below, for example: 然后您可以使用下面的函数引用表达式 ,例如:

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

@holi-java Answer is great, it explains why this problem occurs, here I'm providing a quick fix for those who just want to get rid of the problem: @ holi-java答案很棒,它解释了为什么会出现这个问题,在这里我为那些只想摆脱问题的人提供快速解决方案:

In rxJava2 use io.reactivex.rxkotlin.Observables instead of io.reactivex.Observable to combine your observables: rxJava2使用io.reactivex.rxkotlin.Observables而不是io.reactivex.Observable来组合您的observable:

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

This should work out of the box. 这应该是开箱即用的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM