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

155 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Типы данных
description: Система типов Kotlin, числа, boolean, Char и отсутствие примитивов на уровне языка
tags:
- kotlin
- types
---
В Kotlin: статическая типизация, сильная, с выводом типов.
Главное отличие от Java: **на уровне языка примитивов нет**. Всё - объект, у всего есть методы.
```kotlin
val x: Int = 42
println(x.toString()) // у числа есть методы
println(42.coerceIn(0, 10)) // 10
```
Но в байт-коде `Int` компилируется в `int`, если это возможно - производительность не теряется. Подробнее в [Kotlin в байт-коде](../../Взаимодействие%20с%20Java/Kotlin%20в%20байт-коде.md).
## Иерархия типов
```mermaid
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](../Базовые%20типы%20ООП/Any,%20Unit,%20Nothing.md)
## Числовые типы
| Тип | Размер, бит | Диапазон |
|---|---|---|
| `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`.
### Литералы
```kotlin
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 нет совсем.
```kotlin
val u: UInt = 4_000_000_000u // суффикс u
println(UInt.MAX_VALUE) // 4294967295
```
Нужны редко: работа с бинарными форматами, протоколами, хешами.
## Boolean
```kotlin
val yes: Boolean = true
val both = yes && other() // ленивые операторы, как в Java
val eager = yes and other() // не ленивый: other() вызовется всегда
```
## Char
```kotlin
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](../Работа%20с%20данными/Char.md)
## Преобразования
Неявных расширяющих преобразований нет вообще - только явные вызовы:
```kotlin
val i = 42
val l: Long = i.toLong() // обязательно явно
val b = i.toByte()
val d = i.toDouble()
```
Доступны `toByte()`, `toShort()`, `toInt()`, `toLong()`, `toFloat()`, `toDouble()`, `toChar()`.
## Строки
`String` - неизменяемый тип, элементы доступны по индексу:
```kotlin
val s = "Kotlin"
println(s[0]) // K
println(s.length) // 6
```
Подробнее: [Строки](../Работа%20с%20данными/Строки.md)
## Nullable-типы
Любой тип имеет nullable-вариант с `?`:
```kotlin
// val a: Int = null // ошибка компиляции
val b: Int? = null // ok
```
Это ядро языка, ему посвящён отдельный раздел: [Null-безопасность](../Null-безопасность/Null-безопасность.md)
> [!info] Отличия от Java
> | Java | Kotlin |
> |---|---|
> | `int` и `Integer` - разные типы | только `Int`, компилятор сам выбирает представление |
> | автоупаковка неявная | упаковка скрыта, в коде не видна |
> | `long x = intValue;` работает | нужен `intValue.toLong()` |
> | `char` - числовой тип | `Char` - отдельный тип, не число |
> | нет беззнаковых типов | `UInt`, `ULong`, … |
> | `017` - восьмеричный литерал | восьмеричных литералов нет |
>
> Сравнить: [Типы данных в Java](../../../Программирование%20на%20Java/Синтаксис%20и%20типы/Базовый%20синтаксис/Типы%20данных.md)
> [!warning] Подводные камни
> **Переполнение не проверяется**, как и в Java:
> ```kotlin
> println(Int.MAX_VALUE + 1) // -2147483648
> ```
>
> **Равенство упакованных значений.** Если тип nullable, значение упаковано, и `===` сравнивает ссылки:
> ```kotlin
> 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:
> ```kotlin
> println(0.1 + 0.2) // 0.30000000000000004
> ```
> Для денег - `java.math.BigDecimal`.
Дополнительно: [Числа и переполнение](../Работа%20с%20данными/Числа%20и%20переполнение.md)
Далее: [Переменные](Переменные.md)