为什么在 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 02:51:09  来源:igfitidea点击:

Why do I have to return Unit.INSTANCE when implementing in Java a Kotlin function that returns a Unit?

javakotlinkotlin-interop

提问by Randy Sugianto 'Yuku'

If I have a Kotlin function

如果我有一个 Kotlin 函数

fun f(cb: (Int) -> Unit)

and I want to call ffrom 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 Unitin Kotlin is equivalent to voidin Java?

看起来很丑。为什么我不能像 那样写f(i -> dosomething());,因为Unit在 Kotlin 中相当于void在 Java 中?

回答by Kirill Rakhman

Unitin Kotlin is mostly equivalent to voidin Java, however only when the rules of the JVM allow it.

UnitKotlin 中的大多数情况下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 Unitby the Kotlin compiler is the reason you can write code like:

有趣的事实:UnitKotlin 编译器的特殊处理是您可以编写如下代码的原因:

fun foo() {
    return Unit
}

or

或者

fun bar() = println("Hello World")

Both methods have return type voidin 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) })
}