【问题标题】:Parallel nullable and non-null method with same name具有相同名称的并行可空和非空方法
【发布时间】:2019-02-22 17:05:52
【问题描述】:

我想提供两种可以接受可选或非可选输入的同名方法:

class Formatter {
    fun format(input: Number?) : String? {return number?.toString()}
    fun format(input: Number) : String {return number.toString()}
}

由于 JVM 的限制,这显然是不可能的:

平台声明冲突:以下声明具有相同的 JVM 签名 (test(Lorg.example.Number;)Ljava/lang/String;):

是否有可读的解决方法来实现相同的目标?我目前的解决方案是重命名一种方法(例如 formatNonNull(input: Number))。

奖励:我的 Formatter 类实际上是用 Java 编写的,看起来像这样:

class Formatter {
    @Nullable String format(@Nullable Number input) : String {return number != null ? number.toString(): null;}
}

它应该被非空变体扩展:

@NonNull String formatNonNull(@NonNull Number input) : String {return number.toString();}

有没有办法改进这一点,即不引入新名称(例如,使用 kotlin 扩展名)?

【问题讨论】:

  • 您是否需要 2 个替代方案才能获得适当的可空或不可空返回类型?如果是这种情况,也许contracts 可以帮助你
  • 合同目前不适用于此。到目前为止,我们只能编写对返回值(我们已经拥有的)产生影响的合约,以及执行 Lamba 的次数。我们需要能够根据我们不能(还?)做的函数的输入来指定合约。
  • 即使您可以避免这些方法让编译器感到困惑,它们仍然可能让任何阅读代码的人感到困惑。并且存在调用“错误”方法的真正风险,例如当您期望它时,值不会得到智能转换。我强烈建议要么使这两个等价——在这种情况下,就不需要不可为空的那个——或者给它们不同的名字来解决歧义。

标签: kotlin


【解决方案1】:

有一个巧妙的技巧可以在 JVM 上解决这个问题:

class Formatter {
    fun format(input: Number?) : String? {return number?.toString()}
    @JvmName("-formatNonNull") fun format(input: Number) : String {return number.toString()}
}

之所以起作用,是因为- 在 JVM 字节码中是一个有效的标识符字符,但在 Java 语言中却不是。这意味着代码将编译并且您将能够在 Kotlin 中调用这两个方法,但您将无法从 Java 中调用名称中包含 - 的方法。这也消除了名称冲突,因为方法在字节码中具有不同的名称。

【讨论】:

  • 不幸的是,如果您提供扩展名,这不起作用:@JvmName("-formatNonNull") fun Formatter.format(input: Number): String { return Formatter.format(input) } 似乎不是来解决歧义。但是,将整个 Formatter 类转换为 kotlin 可以达到预期的效果。只是一个小问题:为什么要在 JvmName 前加上“-”?我认为没有理由这样做。
  • 正如我试图解释的那样,函数名称中带有“-”会使 Java 调用站点无法访问它。
  • 显然,该方法无法通过其 JvmName 从 Kotlin 或 Java 代码访问,因此在名称中包含 - 似乎有助于避免潜在的名称冲突。
猜你喜欢
  • 1970-01-01
  • 2016-01-04
  • 1970-01-01
  • 1970-01-01
  • 2018-06-25
  • 1970-01-01
  • 2020-01-06
  • 2017-12-23
  • 1970-01-01
相关资源
最近更新 更多