更改kotlin扩展函数接收器JVM名称

Gil*_*eig 6 java java-interop kotlin kotlin-interop

这是一个普遍的问题.假设我有一个用kotlin编写的扩展函数,它将DP转换为PX并返回一个NonNull Int

fun Int.toPx() {  /** implementation */ }
Run Code Online (Sandbox Code Playgroud)

java中的函数看起来像这样

public int toPx(int $receiver) {  /** implementation */ }
Run Code Online (Sandbox Code Playgroud)

在我看来,这$receiver使得Java-interop感觉生成和不受欢迎.

我知道你可以使用@JvmName注释和一些组合@file:JvmName来改变java中的名字.

当我尝试使用@JvmNamereceiver网站的目标,它说

"此注释不适用于目标type usage和使用站点目标@receiver"

有没有办法克服这一点并改变接收器的名称,如果不是最好的选择.

hot*_*key 7

@JvmName 只能应用于文件的函数,属性访问器和顶级包外观,不支持参数名称.

基本上,您可以定义两个函数,一个采用简单参数,另一个采用接收器:

fun toPx(value: Int) { /* implementation */ }

fun Int.toPx() = toPx(this)
Run Code Online (Sandbox Code Playgroud)

但是,预计足够,这将无法编译,因为这两个函数将具有相同的JVM签名.因此,要消除它们的歧义,请添加@JvmName("...")到扩展名并(可选)标记扩展名inline将其从Java中隐藏:

fun toPx(value: Int) { /* implementation */ }

@JvmName("toPxExtension") @Suppress("nothing_to_inline")
inline fun Int.toPx() = toPx(this)
Run Code Online (Sandbox Code Playgroud)

使内联扩展的替代方法是使用它进行注释@JvmSynthetic.但是,内联也将取消呼叫开销.

此解决方案的缺点是顶级功能toPx泄漏到查看程序包的文件的IDE完成范围.