我创建了一个界面:
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 - () - >单元?
我做错了什么?
答案 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接口的实现是不必要的 不支持的。
如果要在参数中使用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 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 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);
});
}
- 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);
});
}
- 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);
});
}