Kotlin 认为两个方法具有相同的 JVM 签名,但实际上并没有



我来自C#后台,我知道如何在C#中实现这一点,但我正在与Kotlin作斗争。我有两个扩展功能:

fun <T> Foo<T>.myFunction(func: () -> Unit): Foo<T>

fun <T> Foo<T>.myFunction(func: () -> Foo<T>): Foo<T>

显然,func的返回类型在两个函数中都不同。第一个函数执行它并返回this,第二个函数执行func并返回func的结果。但它给了我一个错误:

"平台声明冲突:以下声明具有相同的JVM签名"。

如何在Kotlin中正确实现这一点?

由于类型擦除,您的函数在JVM中有一个冲突的签名(内部Function0<T>类用于表示函数参数(;您可以通过给每个JVM指定一个名称来解决这个问题。从Kotlin,您仍然可以使用原始名称访问它们,但从Java或内部实际使用了另一个名称。只需在备选版本上使用@JvmName注释:

fun <T> Foo<T>.myFunction(func: () -> Unit): Foo<T>
@JvmName("myfunctionWithFoo")   
fun <T> Foo<T>.myFunction(func: () -> Foo<T>): Foo<T>

在JVM上,我们必须与类型擦除作斗争。本质上意味着类型(在本例中为T(在编译的字节码中被丢弃,并且所需的检查只在编译时进行。考虑到这一点,您在查看函数声明时必须牢记这一点。

在这两种情况下,Kotlin都会将函数参数定义为Function0。因为类型被擦除,所以() -> Unit() -> Foo<T>在字节码中看起来都一样。我们可以通过反编译您提供的代码来证明这一点(我重命名了其中一个myFunction2以使其工作(:

public final class com/ginsberg/KotlinStuffKt {
public final static myFunction(Lcom/ginsberg/Foo;Lkotlin/jvm/functions/Function0;)Lcom/ginsberg/Foo;
public final static myFunction2(Lcom/ginsberg/Foo;Lkotlin/jvm/functions/Function0;)Lcom/ginsberg/Foo;
}

这就是Kotlin编译器正在生成的内容(它做得更多,但我已经从这个例子中删除了非必要的部分(。正如你所看到的,由于类型擦除,我们的类型消失了。如果我们撤消我的更改(myFunction2变成myFunction(,就根本无法区分这些更改。这就是编译器抱怨的地方——如果你删除了类型,JVM就无法区分这些函数。

最新更新