Added kotlin guide. (WIP) (15.10.26)
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user