繁体   English   中英

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

[英]Changing kotlin extension function receiver JVM name

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

fun Int.toPx() {  /** implementation */ }

java中的函数看起来像这样

public int toPx(int $receiver) {  /** implementation */ }

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

我知道您可以使用@JvmName注释和@file:JvmName类的组合来更改java中的名称。

当我试图将@JvmNamereceiver站点目标一起使用@JvmName ,它说

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

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

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

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

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

fun Int.toPx() = toPx(this)

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

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

@JvmName("toPxExtension") @Suppress("nothing_to_inline")
inline fun Int.toPx() = toPx(this)

要从Java隐藏扩展函数,您还可以使用@JvmSynthetic对其进行@JvmSynthetic

这个解决方案的缺点是顶层函数toPx泄漏到查看包的文件的IDE完成范围。

参数名称仅在Java中与文档相关(作为IDE中的方法签名提示,当您调用方法时)。 与Kotlin不同,它从不是调用代码的一部分。

如果您在现有类型上定义扩展方法,我发现一个好方法是以描述接收器的方式命名文件。 虽然这对Kotlin无关紧要(因为扩展方法将在没有文件名的情况下调用),但它适用于其他JVM语言。 因此,接收器类型/含义不是由参数名称表示,而是由类名表示。

你已经知道了@file:JvmName ,所以使用它有利于你:

@file:JvmName("Ints")

fun Int.toPx() { ... }

在Kotlin:

val value = 328
val px = value.toPx()

在Java中,代码非常接近Kotlin对应的代码:

int value = 328;
Pixel px = Ints.toPx(value);

当然可以是更长的名称,如IntExtensions如果这有助于可读性。

请注意,在Kotlin中,明确允许在多个文件中的@file:JvmName重用相同的类名,并且扩展函数将组合在一个JVM类中(另请参见此处 )。 你需要注释@file:JvmMultifileClass

因此,您还可以使Int扩展与另一个文件中的像素完全无关,但它仍然会在同一Java类Ints

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM