以下Kotlin代码:
val x = null + null
导致x
属于String
类型,根据String.plus
的文档,这是正确的:
将此字符串与给定[other]对象的字符串表示形式连接起来。如果接收者或[其他]对象为空,则表示为字符串" null"。
但是,我不明白为什么会发生这种情况 - 是否是由于该语言的一些特殊功能?
答案 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?
的类型,即Nothing
或null
。它有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
利用我上面提到的那些强制规则