【问题标题】:Changing kotlin extension function receiver JVM name更改 kotlin 扩展函数接收器 JVM 名称
【发布时间】:2018-05-26 07:55:45
【问题描述】:

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

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

java中的函数看起来像这样

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

在我看来,$receiver 让 Java 互操作感觉生成且不受欢迎。

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

当我尝试将@JvmNamereceiver 站点目标一起使用时,它会说

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

有没有办法克服这个问题并更改接收者的名称,如果没有,最好的选择是什么。

【问题讨论】:

    标签: java kotlin kotlin-interop java-interop


    【解决方案1】:

    @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隐藏扩展功能,也可以annotate it with @JvmSynthetic

    此解决方案的缺点是顶级函数toPx 泄漏到看到包的文件的 IDE 完成范围内。

    【讨论】:

    • 为了实现 java-interop 似乎需要做很多工作和代码重用
    • inline 修饰符不会对 Java 隐藏函数
    • @Gil Java 互操作从一开始就在那里,没有任何工作。是的,参数名称不直观,但它工作得很好。仅需要额外的工作是因为您不想在 Java 中完成时将 $receiver 视为参数名称。不幸的是,没有注释可以完成您想要的操作,因此您可以做出选择。使用丑陋的名字,添加一个额外的方法,或者将调用者转换为 Kotlin ;)
    【解决方案2】:

    参数名称仅在 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 类中(另请参见 here)。为此,您需要注释 @file:JvmMultifileClass

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

    【讨论】:

    • 这是一个选项,但我不认为这是一个等效的转换/选项,我觉得它可以由 Kotlin 团队修复,并使 Java 互操作看起来更少
    猜你喜欢
    • 2020-03-03
    • 2020-08-29
    • 1970-01-01
    • 2022-01-27
    • 1970-01-01
    • 1970-01-01
    • 2019-02-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多