如何使用相同的参数类型重载函数但其中一个可以为空

Mos*_*ius 3 kotlin

我正在尝试向CalendarAndroid中的Class 添加两个扩展功能,以将特定的日期时间模式转换为Calendar,反之亦然

fun Calendar.fromIsoString(date: String): Calendar = this.apply {
    time = SimpleDateFormat(SERVER_DATE_PATTERN, Locale.US).parse(date)
}

fun Calendar.fromIsoString(date: String?): Calendar? {
    if (date == null) return null
    time = SimpleDateFormat(SERVER_DATE_PATTERN, Locale.US).parse(date)
    return this
}
Run Code Online (Sandbox Code Playgroud)

但这给了我以下错误:

平台声明冲突:以下声明具有相同的JVM签名(fromIsoString(Ljava / util / Calendar; Ljava / lang / String;)Ljava / util / Calendar;)

是否可以同时具有这两个功能?怎么样?

注意:我通过向Unit其中一个功能添加可选参数来解决该问题:

fun Calendar.fromIsoString(date: String?, a: Unit = Unit): Calendar? {
if (date == null) return null
    time = SimpleDateFormat(SERVER_DATE_PATTERN, Locale.US).parse(date)
    return this
}
Run Code Online (Sandbox Code Playgroud)

但是我认为这很棘手,不是一个好习惯!有更好的解决方案吗?

Jay*_*ard 5

有一个简单的解决方案,使您无需更改方法或要从Kotlin调用它们的名称即可执行此操作。

对于Kotlin,这两种方法之间的区别很明显,但是对于JVM,则不是。因此,只需告诉Kotlin,您想要一种完全不影响Kotlin代码的方法的内部JVM名称即可。只有Java代码会看到备用名称。例如:

fun Calendar.fromIsoString(date: String): Calendar = this.apply {
    // ... your code without change
}

@JvmName("fromIsoStringNullable") // <-- this solves your problem without changing the name in Kotlin
fun Calendar.fromIsoString(date: String?): Calendar? {
    // ... your code without change
}
Run Code Online (Sandbox Code Playgroud)

瞧!没有更多的错误!您可以使用相同的名称从Kotlin调用任一版本someCalendar.fromIsoString(...)

其他答案和评论表明,可空性是语法糖,远非正确的。这些类型作为额外的元数据写入字节码,只有Kotlin才能看到和执行。但最重要的是,它还@Nullable为参数添加了注释。实际上,所有Kotlin生成的函数参数在字节码中都有@NotNull@Nullable注释,以便其他语言或分析器查看和执行它们是否足够在意它们。