为什么在Kotlin中隐式地使用了null + nulltypes的字符串?

以下Kotlin代码:

val x = null + null 

结果xStringtypes的,根据String.plus的文档是正确的:

将此字符串与给定[other]对象的字符串表示forms连接起来。 如果接收者或[other]对象为空,则表示为字符串“null”。

但是,我不明白为什么会发生这种情况 – 是由于语言的某些特殊function?

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

如果你定义一个接收器types为Int?的扩展函数Int? 而返回types是Int ,那么x将被推断为Int

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

如果你在同一个文件中声明了另一个类似的函数(可以是接收者types的空types),那么当你调用null + null ,会导致编译时错误: Overload resolution ambiguity. All these functions match. Overload resolution ambiguity. All these functions match.

 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 
 val x = null + null 

尝试重写这个如下,你会发现你回答:

 val x = null.plus(null) 

下面是IntelliJ显示的plus方法的签名:

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

所以第一个null被视为String? 键入,然后当你尝试加上其他任何东西时,上面的plus是你唯一的匹配。 打印x将导致nullnull

我们需要从Nothing的types开始。 该types具有完全为零的可能值。 它是一个底部types ,是每个其他types的子types(不要与Any 其他types的超types混淆)。 Nothing都不能强制任何types,所以你可以做这样的事情:

 fun doStuff(a: Int): String = TODO("this typechecks") 

转到Nothing?的typesNothing? ,意思是Nothingnull 。 它有0 + 1个可能的值。 那么null有一种Nothing?Nothing? 可以被强制为任何可空types,所以你可以做这样的东西:

 var name: String? = null 

这里null : Nothing? 被强制为String?

出于某种原因,不幸的是, 在stdlib中定义了这个函数 :

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

允许null + null利用上面提到的那些强制规则