Java Unitを返すKotlin関数を実装するときにUnit.INSTANCEを返す必要があるのはなぜですか?
Kotlin関数がある場合
_fun f(cb: (Int) -> Unit)
_
javaからf
を呼び出したいので、次のようにしなければなりません。
_f(i -> {
dosomething();
return Unit.INSTANCE;
});
_
これは非常にいです。 KotlinのUnit
はJavaのvoid
と同等なので、なぜf(i -> dosomething());
のように書けないのですか?
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>
と同等です。そのため、値を返す必要があります。この問題を回避するために、Javaに戻り値がない場合/戻り値がある場合のための2つの個別のインターフェースConsumer<T>
とFunction<T, R>
があります。
Kotlinの設計者は、機能的なインターフェイスの重複を控え、代わりにコンパイラの「魔法」に依存することにしました。 Kotlinでラムダを宣言する場合、コンパイラが値を挿入するため、値を返す必要はありません。
生活を少し楽にするために、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")
どちらのメソッドも、生成されたバイトコードに戻り型void
がありますが、コンパイラーはそれを把握し、とにかくreturnステートメント/式を使用できるようにするのに十分スマートです。
私はこのアプローチを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) })
}