Всякакви

Това е лесно, Any е само "root" тип, така че всеки друг тип се простира от него. Това е като Object в Java, всъщност компилираният код за стойност от тип Any е Object.

// Котлин

val greeting: Any = "Hi there!"

// Java

private final Object greeting = "Hi there!";

Мерна единица

Функция, връщаща единица в Kotlin, означава връщане на void в Java. Освен това, функция, връщаща Unit в Kotlin, не трябва изрично да го връща. Така че тези две функции се компилират към едно и също:

// Котлин

fun returnsUnit(): Unit {
}
fun returnsUnitExplicitly(): Unit {
    return Unit
}

// Java

public final void returnsUnit() {
}

public final void returnsUnitExplicitly() {
}

Какво е единица тогава?

Единицата се дефинира като единичен екземпляр. Поради тази причина има една валидна стойност за типа:

val unit: Unit = Unit

От гледна точка на йерархията на типа, подобно на всеки друг тип, Unit е дете на Any:

val unit: Any = Unit

Нищо

Нищо не е тип без възможна стойност. Това е така, защото е дефиниран като обикновен клас с частен конструктор. Според документацията: Нищо няма екземпляри. Можете да използвате нищо, за да представите „стойност, която никога не съществува“.

Така че, ако няма начин да се конструира или получи някаква стойност от тип Nothing, как е полезно?

Функции за въвеждане, които никога не се връщат (или хвърлят изключения)

fun infiniteLoop(): Nothing {
    while (true) {
        println("Hi there!")
    }
}

or

fun throwException(): Nothing {
    throw IllegalStateException()
}

Компилаторът е достатъчно умен, за да заключи и в двата случая, че функциите никога няма да се върнат (правилно). Ето защо всеки код, поставен след извикване на функция, връщаща нищо, ще бъде игнориран. Компилаторът ще покаже предупреждение за недостъпен код.

Нека дефинираме нова функция, която може да хвърли изключение (или да върне нула):

fun mayThrowAnException(throwException: Boolean): Nothing? {
    return if (throwException) {
        throw IllegalStateException()
    } else {
        println("Exception not thrown :)")
        null
    }
}

Ако извикаме това от нашата основна:

fun main() {
    val result = mayThrowAnException(true)
    if (result == null) { // Always true
        println("Ignored code")
    }
}

Компилаторът ни подсказва, че резултатът винаги ще бъде нула. Защо е това? Защото единственият начин програмата да продължи след извикване на функцията mayThrowAnExceptionе да върне нула (защото иначе би било Нищо). Ако функцията върне Nothing, това е, защото ще хвърли изключение, което ще доведе до прекъсване на нашата програма.

Преобразуване на throw и return в изрази

Замисляли ли сте се защо това е възможно?

val nullableValue: String? = null
val value = nullableString ?: throw IllegalStateException()

nullableString е от тип String?, а throw IllegalStateException() е нищо. Случва се Нищото да е подтип на всеки тип. Това е причината този израз най-накрая да се изчисли като низ.

Друг пример:

val nullableValue: String? = null
val value: Int = nullableValue?.toInt() ?: return

Този случай е подобен на предишния, но вместо да хвърлим изключение, ние просто се връщаме от функциите. Типът на return е нищо, така че същото като по-горе.

В крайна сметка езикът „преобразува“ както return, така и throw в изрази (чийто тип е Nothing), което води до по-сбито програмиране (вместо да бъдат „изключителни“ изрази).

Къде е нищо в йерархията на типове?

В началото на статията казахме, че Any е на върха на системата от типове. Нищо не е обратното, не е на дъното. Какво означава това? Това означава, че Нищото е подтип на всеки тип. Ето защо примерите за код, показани по-горе, са валидни. Нека прегледаме последната част от предишния пример:

nullableValue?.toInt() ?: return

nullableValue?.toInt е от тип Int? и след това използваме оператора elvis до return от функцията в случай, че nullableValue е null. И типът на израза за връщане е Нищо.

Така че картографиране към типове ще имаме:

Int? ?: Nothing

Върнатият тип на целия израз е типът, който и двата типа имат общо. Тъй като Nothing е подтип на всеки тип, Int? е общото между тях. Като обобщение, общият тип между тип T и Nothing винаги ще бъде T.