为什么在Kotlin中null * null的类型是隐式String?

时间:2017-11-07 16:32:13

标签: string kotlin nullable

以下Kotlin代码:

val x = null + null

导致x属于String类型,根据String.plus的文档,这是正确的:

  

将此字符串与给定[other]对象的字符串表示形式连接起来。如果接收者或[其他]对象为空,则表示为字符串" null"。

但是,我不明白为什么会发生这种情况 - 是否是由于该语言的一些特殊功能?

3 个答案:

答案 0 :(得分:43)

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

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

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

如果在同一个文件中声明另一个类似的函数(可接受类型为可接受类型),则在调用null + null时,会导致编译时错误: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

答案 1 :(得分: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

答案 2 :(得分:4)

我们需要从Nothing的类型开始。此类型的值可能为零。它是bottom type,是所有其他类型的子类型(不要与Any混淆,这是supertype of every other type)。 Nothing可以强制为任何类型,以便您可以执行以下操作:

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

转到Nothing?的类型,即Nothingnull。它有0 + 1个可能的值。因此null的类型为Nothing?Nothing?可以强制为任何可以为空的类型,以便您可以执行以下操作:

var name: String? = null

此处null : Nothing?被强制转移到String?

出于某种原因,不幸的是,有this function defined in stdlib

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

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