为什么在Kotlin中,null + null的类型隐式转换为String类型?

32
以下是 Kotlin 代码:
val x = null + null

x 的类型为 String 是正确的,因为根据 String.plus 的文档:

将此字符串与给定 [other] 对象的字符串表示连接起来。 如果接收器或 [other] 对象中的任何一个为 null,则它们将表示为字符串 "null"。

然而,我不明白为什么会这样 - 这是由于语言的某些特殊功能吗?


1
这里有一个问题吗?引用块解释了为什么x是一个字符串。 - Martin Joiner
@MartinJoiner 对我来说,第一个参数“null”是字符串仍然很奇怪。 - Morozov
5
请提供引用该语句的参考资料。 - Cody G
@CodyG. 你可以在Android Studio中编写null.plus(null),然后当你切换到该方法时,你就能够读取注释了。 - Morozov
1
引用来自plus()运算符。在这里:https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/plus.html - Mauker
3个回答

46

可能是因为在 Kotlin 库中,String?.plus(Any?) 是唯一一个接受可为空类型作为接收者的 plus 函数。因此,当您调用 null + null 时,编译器将把第一个 null 视为 String?

如果您定义了一个扩展函数,其中接收者类型为 Int?,返回类型为 Int,那么 x 将被推断为 Int

public operator fun Int?.plus(other: Any?): Int = 1
val x = null + null

如果您在同一文件中声明了另一个类似的函数(以接收器类型为可空类型),当您调用null + null时,它会导致编译时错误:重载决议模糊。所有这些函数都匹配。

public operator fun Int?.plus(other: Any?): Int = 1
public operator fun Float?.plus(other: Any?): Float = 1F
val x = null + null    //compile time error

6
我们需要从Nothing类型开始。该类型有零个可能的值。它是一个底部类型,是每个其他类型的子类型(不要与Any混淆,后者是每个其他类型的超类型)。Nothing可以强制转换为任何类型,因此您可以执行以下操作:
fun doStuff(a: Int): String =
    TODO("this typechecks")

转到类型 Nothing?,意思是 Nothingnull。它有 0 + 1 种可能的值。所以 null 的类型是 Nothing?Nothing? 可以强制转换为任何可为空的类型,这样你就可以做一些事情,例如:
var name: String? = null

这里将 null : Nothing? 强制转换为 String?

不幸的是,由于某种原因,在标准库中定义了此函数

operator fun String?.plus(other: Any?): String

这允许利用我上面提到的强制类型转换规则进行 null + null 的操作。


3
我感觉这有些像 JavaScript。 - Nikita Kukushkin

4
val x = null + null

尝试按照以下方式重新表述,你会找到答案:

val x = null.plus(null)

下面是IntelliJ显示的plus方法的签名:
public operator fun String?.plus(other: Any?): String

因此,第一个null被视为String?类型,当您尝试加上其他任何东西时,上面的plus方法是您唯一的匹配项。打印x将导致nullnull

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接