Files
obsidian/Kotlin/Синтаксис и типы/Базовый синтаксис/Типы данных.md
T

6.4 KiB
Raw Blame History

title, description, tags
title description tags
Типы данных Система типов Kotlin, числа, boolean, Char и отсутствие примитивов на уровне языка
kotlin
types

В Kotlin: статическая типизация, сильная, с выводом типов.

Главное отличие от Java: на уровне языка примитивов нет. Всё - объект, у всего есть методы.

val x: Int = 42
println(x.toString())      // у числа есть методы
println(42.coerceIn(0, 10))  // 10

Но в байт-коде Int компилируется в int, если это возможно - производительность не теряется. Подробнее в Kotlin в байт-коде.

Иерархия типов

graph TD
    Any["Any — корень всех non-null типов"]
    Any --> Number
    Any --> Char
    Any --> Boolean
    Any --> String
    Any --> Other["классы, интерфейсы, ..."]
    Number --> Byte
    Number --> Short
    Number --> Int
    Number --> Long
    Number --> Float
    Number --> Double
    Nothing["Nothing — наследник всех типов"]

Any, Unit и Nothing - особые типы, им посвящена отдельная заметка: Any, Unit, Nothing

Числовые типы

Тип Размер, бит Диапазон
Byte 8 −128 … 127
Short 16 −32 768 … 32 767
Int 32 ≈ ±2 млрд
Long 64 ≈ ±9,2 · 10¹⁸
Float 32 ≈ 6-7 значащих цифр
Double 64 ≈ 15-16 значащих цифр

Все наследуются от Number, но не друг от друга: Int не является подтипом Long.

Литералы

val i = 42           // Int по умолчанию
val l = 42L          // Long — суффикс L
val d = 42.0         // Double по умолчанию
val f = 42.0f        // Float — суффикс f
val hex = 0xFF       // 255
val bin = 0b1010     // 10
val big = 1_000_000  // подчёркивания для читаемости

Восьмеричных литералов (017 в Java) в Kotlin нет.

Беззнаковые типы

UByte, UShort, UInt, ULong - то, чего в Java нет совсем.

val u: UInt = 4_000_000_000u   // суффикс u
println(UInt.MAX_VALUE)        // 4294967295

Нужны редко: работа с бинарными форматами, протоколами, хешами.

Boolean

val yes: Boolean = true
val both = yes && other()   // ленивые операторы, как в Java
val eager = yes and other() // не ленивый: other() вызовется всегда

Char

val c: Char = 'A'
println(c.code)          // 65 — числовой код
println(c + 1)           // B — Char + Int даёт Char
println(c.isLetter())    // true

Char не является числом: val n: Int = 'A' не скомпилируется, нужен 'A'.code. Подробнее: Char

Преобразования

Неявных расширяющих преобразований нет вообще - только явные вызовы:

val i = 42
val l: Long = i.toLong()    // обязательно явно
val b = i.toByte()
val d = i.toDouble()

Доступны toByte(), toShort(), toInt(), toLong(), toFloat(), toDouble(), toChar().

Строки

String - неизменяемый тип, элементы доступны по индексу:

val s = "Kotlin"
println(s[0])        // K
println(s.length)    // 6

Подробнее: Строки

Nullable-типы

Любой тип имеет nullable-вариант с ?:

// val a: Int = null  // ошибка компиляции
val b: Int? = null    // ok

Это ядро языка, ему посвящён отдельный раздел: Null-безопасность

[!info] Отличия от Java

Java Kotlin
int и Integer - разные типы только Int, компилятор сам выбирает представление
автоупаковка неявная упаковка скрыта, в коде не видна
long x = intValue; работает нужен intValue.toLong()
char - числовой тип Char - отдельный тип, не число
нет беззнаковых типов UInt, ULong, …
017 - восьмеричный литерал восьмеричных литералов нет

Сравнить: Типы данных в Java

[!warning] Подводные камни Переполнение не проверяется, как и в Java:

println(Int.MAX_VALUE + 1)   // -2147483648

Равенство упакованных значений. Если тип nullable, значение упаковано, и === сравнивает ссылки:

val a: Int = 127
val b: Int? = a
val c: Int? = a
println(b == c)    // true  — сравнение значений
println(b === c)   // true  — кеш Integer для -128..127

val x: Int? = 1000
val y: Int? = 1000
println(x == y)    // true
println(x === y)   // false — за пределами кеша это разные объекты

Вывод: для чисел всегда ==, никогда ===.

Float и Double не точны, это стандарт IEEE 754:

println(0.1 + 0.2)   // 0.30000000000000004

Для денег - java.math.BigDecimal.

Дополнительно: Числа и переполнение Далее: Переменные