Подтвердить что ты не робот

Почему тип NULL + null неявно String в Kotlin?

Следующий код Котлина:

val x = null + null

приводит к тому, что x имеет тип String, что является правильным, как в соответствии с документами для String.plus:

Объединяет эту строку со строковым представлением данного [другого] объекта. Если либо приемник, либо [другой] объект являются нулевыми, они представляются в виде строки "null".

Однако я не понимаю, почему это происходит - это из-за какой-то особой особенности языка?

4b9b3361

Ответ 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 использовать те правила принуждения, о которых я говорил выше