传递lambda而不是接口

时间:2017-04-18 10:07:20

标签: lambda kotlin

我创建了一个界面:

interface ProgressListener {
    fun transferred(bytesUploaded: Long)
}

但只能将其用作匿名类,而不是lambda

dataManager.createAndSubmitSendIt(title, message,
object : ProgressListener {
    override fun transferred(bytesUploaded: Long) {
        System.out.println(bytesUploaded.toString())
    }
})

我认为应该有可能用lambda替换它:

dataManager.createAndSubmitSendIt(title, message, {System.out.println(it.toString())})

但我收到错误:类型不匹配; required - ProgressListener,found - () - >单元?

我做错了什么?

5 个答案:

答案 0 :(得分:32)

正如@ zsmb13所说,SAM转换仅支持Java接口。

您可以创建一个扩展功能,使其工作:

// Assuming the type of dataManager is DataManager.
fun DataManager.createAndSubmitSendIt(title: String, 
                                      message: String, 
                                      progressListener: (Long) -> Unit) {
    createAndSubmitSendIt(title, message,
        object : ProgressListener {
            override fun transferred(bytesUploaded: Long) {
                progressListener(bytesUploaded)
            }
        })
}

答案 1 :(得分:24)

Kotlin仅支持Java接口的SAM转换。

  

...请注意,此功能仅适用于Java互操作;自从Kotlin   具有适当的功能类型,功能自动转换为   因此,Kotlin接口的实现是不必要的   不支持的。

- Official documentation

如果要在参数中使用lambda,请使用函数参数而不是接口。 (至少现在。支持Kotlin接口的SAM转换是一个持续的讨论,它是Kotlin 1.1直播流未来可能的功能之一。)

答案 2 :(得分:7)

派对有点晚了:你不是创建一个界面,而是让编译通过直接使用函数而不是数据管理器中的接口创建一个,如下所示:

fun createAndSubmitSendIt(title: String, message: String, transferred: (Long) -> Unit) {
    val answer = TODO("whatever you need to do")
    transferred(answer)
}

然后你就像你想要的那样使用它!如果我没记错的话,kotlin / jvm编译器的功能与创建接口相同。

希望它有所帮助!

答案 3 :(得分:1)

另一种解决方案是声明一个类型别名,将其注入某个地方并调用它。这里是示例:

internal typealias WhateverListener = (String) -> Unit

然后将类型别名注入我们的类:

class Gallery constructor(private val whateverListener: WhateverListener) {

    ...

    galleryItemClickListener.invoke("hello")

    ...
}

所以我们有lambda:

val gallery = Gallery { appNavigator.openVideoPlayer(it) }

感谢我的同事乔尔·佩德拉萨(Joel Pedraza),他在尝试解决方案时向我展示了诀窍<3。

答案 4 :(得分:0)

如果您希望同时获得Kotlin和Java的最佳访问体验,则没有一个最终的解决方案。

如果Kotlin开发人员不认为不必为Kotlin接口进行SAM转换,那么“ Kotlin接口”方法将是最终解决方案。

  

https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
  另请注意,此功能仅适用于Java互操作。自科特林以来   具有适当的功能类型,功能会自动转换为   Kotlin接口的实现是不必要的,因此   不支持。

为您的用例选择最佳解决方案。

Kotlin函数类型

  
      
  • Kotlin API:完美
  •   
  • 科林访问权限:完美
  •   
  • Java访问:      
        
    • 自动生成的参数类型,例如Function1(对于Java 8 lambda来说不是大问题)
    •   
    • 详细说明return Unit.INSTANCE;而不是无效回报。
    •   
  •   
class KotlinApi {
    fun demo(listener: (response: String) -> Unit) {
       listener("response")
    }
}

fun kotlinConsumer() {
    KotlinApi().demo { success ->
        println(success)
    }
}


public void javaConsumer() {
    new KotlinApi().demo(s -> {
        System.out.println(s);
        return Unit.INSTANCE;
    });
}

Kotlin界面

  
      
  • Kotlin API:其他接口定义。
  •   
  • Kotlin访问权限:太详细了
  •   
  • Java Access:完美
  •   
class KotlinApi {
    interface Listener {
        fun onResponse(response: String)
    }

    fun demo(listener: Listener) {
       listener.onResponse("response")
    }
}

fun kotlinConsumer() {
    KotlinApi().demo(object : KotlinApi.Listener {
        override fun onResponse(response: String) {
            println(response)
        }
    })
}

//If Kotlin had supported SAM conversion for Kotlin interfaces. :(
//fun kotlinConsumer() {
//    KotlinApi().demo {
//        println(it)
//    }
//}

public void javaConsumer() {
    new KotlinApi().demo(s -> {
        System.out.println(s);
    });
}

Java接口

  
      
  • Kotlin API:混合Java代码。
  •   
  • 科特琳通道:有点冗长
  •   
  • Java Access:完美
  •   
class KotlinApi {
    fun demo(listener: Listener) {
        listener.onResponse("response")
    }
}

public interface Listener {
    void onResponse(String response);
}

//Semi SAM conversion
fun kotlinConsumer() {
    KotlinApi().demo(Listener {
        println(it)
    })
}

public void javaConsumer() {
    new KotlinApi().demo(s -> {
        System.out.println(s);
    });
}

多种方法

  
      
  • Kotlin API:多种方法的实现
  •   
  • 科特琳访问:如果使用正确的方法,则完美。自动完成功能还建议使用详细方法。
  •   
  • Java Access:完美。由于JvmSynthetic批注,自动完成功能不建议使用函数类型方法
  •   
class KotlinApi {
    interface Listener {
        fun onResponse(response: String)
    }

    fun demo(listener: Listener) {
        demo {
            listener.onResponse(it)
        }
    }

    @JvmSynthetic //Prevents JVM to use this method
    fun demo(listener: (String) -> Unit) {
        listener("response")
    }
}

fun kotlinConsumer() {
    KotlinApi().demo {
        println(it)
    }
}

public void javaConsumer() {
    new KotlinApi().demo(s -> {
        System.out.println(s);
    });
}

Java API

  
      
  • Kotlin API:没有Kotlin API,所有API代码都是Java
  •   
  • 科特林访问:完美
  •   
  • Java访问权限:完美
  •   
public class JavaApi {
    public void demo(Listener listener) {
        listener.onResponse("response");
    }

    public interface Listener {
        void onResponse(String response);
    }

}

//Full SAM conversion
fun kotlinConsumer() {
    JavaApi().demo {
        println(it)
    }
}

public void javaConsumer() {
    new JavaApi().demo(s -> {
        System.out.println(s);
    });
}