为什么在 Java 中实现返回 Unit 的 Kotlin 函数时必须返回 Unit.INSTANCE?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37828790/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why do I have to return Unit.INSTANCE when implementing in Java a Kotlin function that returns a Unit?
提问by Randy Sugianto 'Yuku'
If I have a Kotlin function
如果我有一个 Kotlin 函数
fun f(cb: (Int) -> Unit)
and I want to call f
from Java, I have to do it like:
我想f
从 Java调用,我必须这样做:
f(i -> {
dosomething();
return Unit.INSTANCE;
});
which looks very ugly. Why can't I just write it like f(i -> dosomething());
, since Unit
in Kotlin is equivalent to void
in Java?
看起来很丑。为什么我不能像 那样写f(i -> dosomething());
,因为Unit
在 Kotlin 中相当于void
在 Java 中?
回答by Kirill Rakhman
Unit
in Kotlin is mostly equivalent to void
in Java, however only when the rules of the JVM allow it.
Unit
Kotlin 中的大多数情况下void
与 Java 中的相同,但是只有在 JVM 的规则允许的情况下。
Functional types in Kotlin are represented by interfaces like:
Kotlin 中的函数类型由以下接口表示:
public interface Function1<in P1, out R> : Function<R> {
/** Invokes the function with the specified argument. */
public operator fun invoke(p1: P1): R
}
When you declare (Int) -> Unit
, from Java's point of view this is equivalent to Function<Integer, Unit>
. That's why you have to return a value. To work around this problem, in Java there are two separate interfaces Consumer<T>
and Function<T, R>
for when you don't have/have a return value.
当您声明 时(Int) -> Unit
,从 Java 的角度来看,这等效于Function<Integer, Unit>
.这就是为什么你必须返回一个值。为了解决这个问题,在 Java 中有两个单独的接口Consumer<T>
,Function<T, R>
当你没有/有返回值时。
The Kotlin designers decided to forgo the duplication of functional interfaces and instead rely on compiler "magic". If you declare a lambda in Kotlin, you don't have to return a value because the compiler will insert one for you.
Kotlin 的设计者决定放弃函数式接口的重复,转而依赖编译器的“魔法”。如果您在 Kotlin 中声明一个 lambda,则不必返回值,因为编译器会为您插入一个值。
To make your life a little bit easier, you can write a helper method that wraps a Consumer<T>
in a Function1<T, Unit>
:
为了让您的生活更轻松,您可以编写一个将 a 包装Consumer<T>
在 a 中的辅助方法Function1<T, Unit>
:
public class FunctionalUtils {
public static <T> Function1<T, Unit> fromConsumer(Consumer<T> callable) {
return t -> {
callable.accept(t);
return Unit.INSTANCE;
};
}
}
Usage:
用法:
f(fromConsumer(integer -> doSomething()));
Fun fact: The special handling of Unit
by the Kotlin compiler is the reason you can write code like:
有趣的事实:Unit
Kotlin 编译器的特殊处理是您可以编写如下代码的原因:
fun foo() {
return Unit
}
or
或者
fun bar() = println("Hello World")
Both methods have return type void
in the generated bytecode but the compiler is smart enough to figure that out and allow you to use return statements/expressions anyway.
这两种方法void
在生成的字节码中都有返回类型,但编译器足够聪明,可以解决这个问题,并允许您无论如何都使用返回语句/表达式。
回答by ultraon
I use this approach for Kotlin & Java. The methods of MyKotlinClass you will see in Java, in Kotlin you will see both methods (class method + extension function).
我将这种方法用于 Kotlin 和 Java。您将在 Java 中看到 MyKotlinClass 的方法,在 Kotlin 中您将看到这两种方法(类方法 + 扩展函数)。
MyKotlinClass {
//Method to use in Java, but not restricted to use in Kotlin.
fun f(cb: Consumer<Int>) { //Java8 Consumer, or any custom with the same interface
int i = getYourInt()
cb.accept(i)
}
}
//Extension for Kotlin. It will be used in Kotlin.
fun MyKotlinClass.f(cb: (Int) -> Unit) {
f(Consumer { cb(it) })
}