当前位置: 首页 > 面试题库 >

使用功能参考在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:((观察者)->单位)!, 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)
    }

}

问题答案:

您还可以像在Java中使用方法引用表达式一样,在Kotlin中使用函数引用表达式。例如,Kotlin中的combine函数引用KFunction3如下:

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

在Java中,“方法引用表达式”可以分配给任何 兼容的* Functional
Interface
,但是即使它们
兼容 ,也不能将“
函数引用表达式”分配给任何Function类型,例如:
*

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

的确,Kotlin使用SAM转换将lambda /
函数引用表达式转换为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();
   }
};

为什么
方法引用表达式在Java中可以正常工作,但是在Kotlin中使用函数引用表达式却失败了?

基于上述内容,您可以看到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 /
函数引用表达式转换为Java Functional
Interface,但是它不能直接分配给Java
Functional
Interface。

combineLatest在Kotlin中方法的第4个参数,编译器根本无法推断其类型,因为第4个参数类型可以是io.reactivex.functions.Function3ObservableSource。因为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) }
}

然后,
您可以使用如下所示的函数引用表达式,例如:

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


 类似资料:
  • 我有一个使用方法引用的示例Java代码,我想重写给Kotlin。Java版本是使用方法参考的,解决方案简明扼要。但另一方面,我不能在Kotlin中使用方法引用。我写的唯一一个版本是下面的一个。看来可以用更干净的方式编写(如果可能,方法引用将是完美的)。 我刚认识Kotlin所以如果有线索我会很感激的。 编辑 Kotlin中的以下方法引用给出了一个错误。 不能使用提供的参数调用以下函数:@Check

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

  • 问题内容: 我成功使用此代码通过方法发送 带有某些参数的请求 现在,我可能需要通过方法发送参数(即param1,param2,param3),因为它们很长。我在想为该方法添加一个额外的参数(即String httpMethod)。 我如何才能尽可能少地更改上面的代码,以便能够通过或发送参数? 我希望改变 至 本来可以解决问题的,但是参数仍然通过GET方法发送。 有没有什么方法会有所帮助?有任何有用

  • get1方法工作正常,但get2存在编译错误: > 类型A.B的方法get2(集合)必须重写或实现超类型方法 只有带有泛型的参数才会出现此错误<代码>get3编译,但当然有一个警告: > 显然还有其他方法可以解决这个问题,但在我的理解中,这应该是一个法律优先事项,我的问题更多的是为什么会有这个编译错误。提前谢谢! 编辑: 对不起,我的例子不够清楚。因此,这里有一个新的答案来回应你的一些观点。 与上

  • 本文向大家介绍Java生成验证码功能实例代码,包括了Java生成验证码功能实例代码的使用技巧和注意事项,需要的朋友参考一下 页面上输入验证码是比较常见的一个功能,实现起来也很简单.给大家写一个简单的生成验证码的示例程序,需要的朋友可以借鉴一下. 闲话少续,直接上代码.代码中的注释很详细. 上面这段代码就能生成一个验证码,略微修改就能生成各种各样的形式,main方法可以测试. 下面为大家写一下如何返