Added kotlin guide. (WIP) (15.10.26)

This commit is contained in:
2026-10-15 00:24:21 +03:00
parent dc82207723
commit da3ad9dd1a
13 changed files with 2120 additions and 0 deletions
@@ -0,0 +1,182 @@
---
title: Операторы и выражения
description: Арифметика, равенство == и ===, побитовые операции словами, приоритет операторов
tags:
- kotlin
- syntax
---
В Kotlin почти все операторы - это вызовы функций. `a + b` компилируется в `a.plus(b)`, поэтому операторы можно определять для своих типов ([Операторные функции](../../Функциональный%20Kotlin/Инфиксные%20и%20операторные%20функции.md)).
## Арифметические
| Оператор | Функция | Пример |
|---|---|---|
| `+` | `plus` | `2 + 3` → 5 |
| `-` | `minus` | `5 - 3` → 2 |
| `*` | `times` | `2 * 3` → 6 |
| `/` | `div` | `7 / 2` → 3 |
| `%` | `rem` | `7 % 2` → 1 |
Целочисленное деление отбрасывает дробную часть:
```kotlin
println(7 / 2) // 3
println(7.0 / 2) // 3.5
println(7 / 2.0) // 3.5
println(-7 / 2) // -3 — округление к нулю
println(-7 % 2) // -1 — знак остатка совпадает со знаком делимого
```
### Инкремент и декремент
```kotlin
var i = 0
println(i++) // 0, потом i = 1
println(++i) // 2
```
Работают только с `var`. Присваивания-операторы (`+=`, `-=`, `*=`, `/=`, `%=`) - тоже.
## Сравнение
`<`, `>`, `<=`, `>=` транслируются в `compareTo`:
```kotlin
println(2 < 3) // true
println("abc" < "abd") // true — лексикографически
```
Работает для любого типа, реализующего `Comparable`.
## Равенство: == и ===
Это главное место, где Kotlin расходится с Java.
| Оператор | Что делает |
|---|---|
| `==` | структурное равенство, вызывает `equals()` |
| `===` | ссылочное равенство, сравнивает адреса |
| `!=`, `!==` | их отрицания |
```kotlin
val a = "Kotlin"
val b = StringBuilder("Kotlin").toString()
println(a == b) // true — содержимое совпадает
println(a === b) // false — разные объекты
```
`==` безопасен для null: `a == b` разворачивается в `a?.equals(b) ?: (b === null)`.
```kotlin
val s: String? = null
println(s == "text") // false, без NPE
println(s == null) // true
```
## Логические
```kotlin
val r1 = true && false // ленивый И
val r2 = true || false // ленивый ИЛИ
val r3 = !true // НЕ
val r4 = true and false // НЕ ленивый — оба операнда вычисляются
val r5 = true or false // НЕ ленивый
val r6 = true xor true // false
```
В обычном коде используют `&&` и `||`: они не вычисляют правую часть, если результат уже известен.
## Побитовые операции
Символов `&`, `|`, `^`, `<<`, `>>` для чисел в Kotlin **нет** - только инфиксные функции:
```kotlin
val a = 0b1100
val b = 0b1010
println(a and b) // 8 = 0b1000
println(a or b) // 14 = 0b1110
println(a xor b) // 6 = 0b0110
println(a.inv()) // -13 — побитовое НЕ
println(1 shl 4) // 16 — сдвиг влево
println(16 shr 2) // 4 — сдвиг вправо со знаком
println(-16 ushr 2) // беззнаковый сдвиг вправо
```
Доступны для `Int` и `Long`.
## Операторы диапазонов и коллекций
```kotlin
println(5 in 1..10) // true
println(5 !in 1..10) // false
println("a" in listOf("a","b")) // true — вызывает contains()
val list = listOf(1, 2)
println(list + 3) // [1, 2, 3] — plus для коллекций
```
Подробнее: [Циклы и диапазоны](Циклы%20и%20диапазоны.md)
## Приоритет
От высшего к низшему:
| Уровень | Операторы |
|---|---|
| постфиксные | `++`, `--`, `.`, `?.`, `!!` |
| префиксные | `-`, `+`, `++`, `--`, `!` |
| приведение | `as`, `as?` |
| умножение | `*`, `/`, `%` |
| сложение | `+`, `-` |
| диапазон | `..`, `..<` |
| инфиксные функции | `and`, `shl`, своя функция `infix` |
| проверка принадлежности | `in`, `!in` |
| проверка типа | `is`, `!is` |
| сравнение | `<`, `>`, `<=`, `>=` |
| равенство | `==`, `!=`, `===`, `!==` |
| конъюнкция | `&&` |
| дизъюнкция | `\|\|` |
| elvis | `?:` |
| присваивание | `=`, `+=`, … |
На практике: сомневаетесь - ставьте скобки.
## Всё является выражением
`if`, `when`, `try` возвращают значение:
```kotlin
val max = if (a > b) a else b
val name = when (code) {
200 -> "ok"
else -> "unknown"
}
val n = try { text.toInt() } catch (e: NumberFormatException) { 0 }
```
Подробнее: [Условные конструкции](Условные%20конструкции.md)
Циклы (`for`, `while`) - **не** выражения, они возвращают `Unit`.
> [!info] Отличия от Java
> | Java | Kotlin |
> |---|---|
> | `==` для объектов - ссылки | `==` - вызов `equals()` |
> | `.equals()` - содержимое | `===` - ссылки |
> | `a & b` побитовое И | `a and b` |
> | `a >>> b` | `a ushr b` |
> | `~a` | `a.inv()` |
> | тернарник `c ? a : b` | `if (c) a else b` |
> | операторы нельзя перегружать | можно, через `operator fun` |
> | `s.equals(t)` падает, если `s` null | `s == t` безопасен |
>
> Главная ловушка при переходе: в Java `==` на строках сравнивает ссылки и работает «случайно» благодаря [интернированию](../../../Программирование%20на%20Java/Синтаксис%20и%20типы/Работа%20с%20данными%20и%20типами/Строки.md). В Kotlin `==` всегда сравнивает содержимое - это и нужно в 99% случаев.
>
> Сравнить: [Операторы в Java](../../../Программирование%20на%20Java/Синтаксис%20и%20типы/Базовый%20синтаксис/Операторы%20и%20выражения.md)
> [!warning] Подводные камни
> **`and` и `or` не ленивые.** Для `Boolean` это рабочий код, но правая часть вычислится всегда:
> ```kotlin
> fun risky(): Boolean { println("вызвана"); return true }
> val a = false && risky() // risky() не вызовется
> val b = false and risky() // "вызвана" напечатается
> ```
>
> **Деление на целочисленный ноль - исключение, на вещественный - нет:**
> ```kotlin
> // println(1 / 0) // ArithmeticException
> println(1.0 / 0) // Infinity
> println(0.0 / 0) // NaN
> println(Double.NaN == Double.NaN) // false! NaN не равен себе
> ```
>
> **Приоритет инфиксных функций ниже арифметики:**
> ```kotlin
> println(1 shl 2 + 3) // 32, а не 7: это 1 shl (2+3)
> println((1 shl 2) + 3) // 7
> ```
>
> **`++` на упакованном значении создаёт новый объект** - в горячем цикле с `Int?` это аллокации. Используйте не-nullable типы.
Далее: [Условные конструкции](Условные%20конструкции.md)