Почему тип NULL + null неявно String в Kotlin?
Следующий код Котлина:
val x = null + null
приводит к тому, что x
имеет тип String
, что является правильным, как в соответствии с документами для String.plus
:
Объединяет эту строку со строковым представлением данного [другого] объекта. Если либо приемник, либо [другой] объект являются нулевыми, они представляются в виде строки "null".
Однако я не понимаю, почему это происходит - это из-за какой-то особой особенности языка?
Ответы
Ответ 1
Вероятно, потому что 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
это вызывает ошибку времени компиляции: 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
Ответ 2
val x = null + null
Попробуйте перефразировать это, как показано ниже, и вы найдете ответ:
val x = null.plus(null)
Ниже показано, что IntelliJ показывает как подпись метода plus
:
public operator fun String?.plus(other: Any?): String
Итак, первый null
рассматривается как тип String?
, а затем, когда вы пытаетесь добавить что-либо еще, указанный выше метод plus
является единственным вашим совпадением. Распечатка x
приведет к nullnull
Ответ 3
Нам нужно начать с типа Nothing
. Этот тип имеет ровно нулевые возможные значения. Это нижний тип и является подтипом любого другого типа (не путать с Any
, который является супертип любого другого типа). Nothing
можно принуждать к любому типу, так что вы можете делать такие вещи, как:
fun doStuff(a: Int): String =
TODO("this typechecks")
Переход к типу Nothing?
, что означает Nothing
или null
. Он имеет 0 + 1 возможных значений. Итак, null
имеет тип Nothing?
. Nothing?
может быть принудительно применен к любому нулевому типу, так что вы можете делать такие вещи, как:
var name: String? = null
Здесь null : Nothing?
принуждается к String?
.
По какой-то причине, к сожалению, эта функция определена в stdlib:
operator fun String?.plus(other: Any?): String
что позволяет null + null
использовать те правила принуждения, о которых я говорил выше