为什么我必须 return Unit.INSTANCE 在 Java 中实现一个 return 是一个单元的 Kotlin 函数?
Why do I have to return Unit.INSTANCE when implementing in Java a Kotlin function that returns a Unit?
如果我有一个 Kotlin 函数
fun f(cb: (Int) -> Unit)
我想从 Java 调用 f
,我必须这样做:
f(i -> {
dosomething();
return Unit.INSTANCE;
});
看起来很丑。为什么我不能像 f(i -> dosomething());
这样写,因为 Kotlin 中的 Unit
等同于 Java 中的 void
?
Kotlin 中的 Unit
基本上等同于 Java 中的 void
,但是仅当 JVM 的规则允许时。
Kotlin 中的函数类型由如下接口表示:
public interface Function1<in P1, out R> : Function<R> {
/** Invokes the function with the specified argument. */
public operator fun invoke(p1: P1): R
}
当您声明 (Int) -> Unit
时,从 Java 的角度来看,这等同于 Function<Integer, Unit>
。这就是为什么你必须 return 一个值。要解决此问题,在 Java 中有两个单独的接口 Consumer<T>
和 Function<T, R>
,当您没有 have/have 一个 return 值时。
Kotlin 设计者决定放弃函数接口的重复,转而依赖编译器 "magic"。如果您在 Kotlin 中声明一个 lambda,则不必 return 一个值,因为编译器会为您插入一个值。
为了让您的生活更轻松一些,您可以编写一个辅助方法,将 Consumer<T>
包装在 Function1<T, Unit>
中:
public class FunctionalUtils {
public static <T> Function1<T, Unit> fromConsumer(Consumer<T> callable) {
return t -> {
callable.accept(t);
return Unit.INSTANCE;
};
}
}
用法:
f(fromConsumer(integer -> doSomething()));
有趣的事实:Kotlin 编译器对 Unit
的特殊处理是您可以编写如下代码的原因:
fun foo() {
return Unit
}
或
fun bar() = println("Hello World")
这两种方法在生成的字节码中都有 return 类型 void
,但编译器足够聪明,可以识别并允许您使用 return statements/expressions。
我将这种方法用于 Kotlin 和 Java。您将在 Java 中看到 MyKotlinClass 的方法,在 Kotlin 中您将看到这两种方法(class 方法 + 扩展函数)。
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) })
}
如果我有一个 Kotlin 函数
fun f(cb: (Int) -> Unit)
我想从 Java 调用 f
,我必须这样做:
f(i -> {
dosomething();
return Unit.INSTANCE;
});
看起来很丑。为什么我不能像 f(i -> dosomething());
这样写,因为 Kotlin 中的 Unit
等同于 Java 中的 void
?
Unit
基本上等同于 Java 中的 void
,但是仅当 JVM 的规则允许时。
Kotlin 中的函数类型由如下接口表示:
public interface Function1<in P1, out R> : Function<R> {
/** Invokes the function with the specified argument. */
public operator fun invoke(p1: P1): R
}
当您声明 (Int) -> Unit
时,从 Java 的角度来看,这等同于 Function<Integer, Unit>
。这就是为什么你必须 return 一个值。要解决此问题,在 Java 中有两个单独的接口 Consumer<T>
和 Function<T, R>
,当您没有 have/have 一个 return 值时。
Kotlin 设计者决定放弃函数接口的重复,转而依赖编译器 "magic"。如果您在 Kotlin 中声明一个 lambda,则不必 return 一个值,因为编译器会为您插入一个值。
为了让您的生活更轻松一些,您可以编写一个辅助方法,将 Consumer<T>
包装在 Function1<T, Unit>
中:
public class FunctionalUtils {
public static <T> Function1<T, Unit> fromConsumer(Consumer<T> callable) {
return t -> {
callable.accept(t);
return Unit.INSTANCE;
};
}
}
用法:
f(fromConsumer(integer -> doSomething()));
有趣的事实:Kotlin 编译器对 Unit
的特殊处理是您可以编写如下代码的原因:
fun foo() {
return Unit
}
或
fun bar() = println("Hello World")
这两种方法在生成的字节码中都有 return 类型 void
,但编译器足够聪明,可以识别并允许您使用 return statements/expressions。
我将这种方法用于 Kotlin 和 Java。您将在 Java 中看到 MyKotlinClass 的方法,在 Kotlin 中您将看到这两种方法(class 方法 + 扩展函数)。
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) })
}