当前位置: 首页 > 知识库问答 >
问题:

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

黎玺
2023-03-14

我有一个使用方法引用的示例Java代码,我想重写给Kotlin。Java版本是使用方法参考的,解决方案简明扼要。但另一方面,我不能在Kotlin中使用方法引用。我写的唯一一个版本是下面的一个。看来function3{s:String,b:Boolean,i:Int->combine(s,b,i)}可以用更干净的方式编写(如果可能,方法引用将是完美的)。

我刚认识Kotlin所以如果有线索我会很感激的。

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

编辑

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:(Observer)->Unit)!,p3:((???,???,???)->???)!):Observable<(???..???)>!在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)
    }

}

共有1个答案

水飞掣
2023-03-14

您也可以在Kotlin中使用函数引用表达式,就像在Java中使用方法引用表达式一样。例如,combine函数引用为Kotlin中的Kfunction3,如下所示:

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/function引用表达式转换为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();
   }
};

基于以上内容,您可以看到RX-Java2中有许多重载的combineLatest方法。例如,以下两个就不能让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/function引用表达式转换为Java函数接口,但它不能直接赋值给Java函数接口。

Kotlin中combineLatest方法的第4个参数,编译器根本无法推断其类型,因为第4个参数类型可以是io.reactivex.functions.function3observableSource。因为observableSource也是一个Java函数接口。

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

那么可以使用函数引用表达式如下所示,例如:

Observable.combineLatest(
        strings(),
        booleans(), 
        integers(), 
        //             v--- convert KFunction3 to RxFunction3 explicitly
        this::combine.toFunction3()
)
 类似资料:
  • 问题内容: 我有一个使用方法引用的示例Java代码,我想将其重写为Kotlin。Java版本正在使用方法参考,解决方案简短明了。但是另一方面,我不能在Kotlin中使用方法引用。我设法编写的唯一版本是下面介绍的版本。似乎可以用更简洁的方式编写(如果可能的话,方法引用将是完美的)。 我是Kotlin的新手,所以我将不胜感激。 爪哇 科特林 编辑 以下Kotlin中的方法引用给出了错误。 使用提供的参

  • 当从期望SAM(单抽象方法)类型参数的Java API调用方法时,是否有一致的方法将函数文字强制为正确的类型?我发现,有时Kotlin函数可以很好地工作,而其他函数似乎没有任何一致性。 我有几个来自Ratpack API的示例: 调用ChainAction时。handler(String,handler)使用Kotlin函数文字效果很好,例如: 类型推断发现上下文是一个ratpack。处理。背景

  • 从Kotlin调用Java代码时,存在SAM转换,因此Java代码如下所示: 可以如下所示: 现在,我正在处理一个Kotlin项目,我想将功能接口定义为事件侦听器: 在SomeClass中,我有一个设置监听器的函数: 当我创建这个类的实例并尝试调用setter函数时,我是这样做的: 我知道静态编程语言有函数类型,因此不支持来自各种站点的SAM转换,例如这个站点。 我读过一些关于函数类型的书,但我以

  • 如何从web3j库中引用数组类型?我有一个契约函数,它返回访问该契约的人的地址数组。我想把这些作为数组放到java/kotlin项目中。这是代码-

  • 在上面,我有类似的10个if条件,如何避免上面的重复代码?我需要使用任何Java8个函数类作为参数来避免重复代码(或者)必须使用任何额外的泛型代码吗?

  • 让我们假设我在科特林有一门课,如下所示 此外,让我们定义一个内插函数生成电子邮件域,它基于给定域的名称生成电子邮件地址 现在,正如有人说Kotlin是100%可与Java互操作的,我如何在Java类中使用这个中缀函数? 上面使用infix可能不合适,但我想知道如何在Java中使用。 如果我的理解有误,请纠正。