Added kotlin guide. (WIP) (15.10.26)
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
---
|
||||
title: Переменные
|
||||
description: val и var, вывод типов, const val, lateinit и области видимости
|
||||
tags:
|
||||
- kotlin
|
||||
- syntax
|
||||
---
|
||||
|
||||
Два ключевых слова:
|
||||
- `val` - **value**, значение присваивается один раз (read-only)
|
||||
- `var` - **variable**, значение можно менять
|
||||
|
||||
```kotlin
|
||||
val name = "Kotlin"
|
||||
var count = 0
|
||||
count++ // ok
|
||||
// name = "Java" // ошибка компиляции: val cannot be reassigned
|
||||
```
|
||||
|
||||
Правило стиля: по умолчанию `val`, `var` - только когда переменная действительно меняется. Это не формальность: с `val` работают [умные приведения](../Null-безопасность/Умные%20приведения.md), а код становится предсказуемее.
|
||||
|
||||
## Объявление
|
||||
```kotlin
|
||||
val a: Int = 1 // тип указан явно
|
||||
val b = 1 // тип выведен: Int
|
||||
val c: Int // без инициализации — тип обязателен
|
||||
c = 2 // присвоить можно позже, но только один раз
|
||||
```
|
||||
Тип ставится **после** имени через двоеточие.
|
||||
|
||||
## Вывод типов
|
||||
Компилятор выводит тип из значения:
|
||||
```kotlin
|
||||
val n = 42 // Int
|
||||
val l = 42L // Long
|
||||
val s = "text" // String
|
||||
val list = listOf(1, 2) // List<Int>
|
||||
val mixed = listOf(1, "a") // List<Any>
|
||||
```
|
||||
Вывод работает только там, где есть что выводить. У свойств класса и возвращаемых значений публичных функций тип лучше писать явно - это часть контракта.
|
||||
|
||||
## val - не значит immutable
|
||||
`val` запрещает переприсваивание ссылки, но не меняет сам объект:
|
||||
```kotlin
|
||||
val list = mutableListOf(1, 2)
|
||||
list.add(3) // ok — меняем объект
|
||||
println(list) // [1, 2, 3]
|
||||
// list = mutableListOf() // ошибка — меняем ссылку
|
||||
```
|
||||
Неизменяемость данных - это выбор типа (`List` вместо `MutableList`), а не `val`. Подробнее: [Изменяемость коллекций](../../Коллекции/Изменяемость.md)
|
||||
|
||||
## val с геттером
|
||||
`val` может вычисляться при каждом обращении:
|
||||
```kotlin
|
||||
val now: Long
|
||||
get() = System.currentTimeMillis()
|
||||
```
|
||||
Это уже свойство, а не поле. Подробнее: [Свойства](../../ООП/Свойства.md)
|
||||
|
||||
## Константы - const val
|
||||
```kotlin
|
||||
const val MAX = 100 // верхний уровень файла
|
||||
const val GREETING = "Hello"
|
||||
|
||||
object Config {
|
||||
const val TIMEOUT = 30 // или внутри object
|
||||
}
|
||||
```
|
||||
Требования к `const val`:
|
||||
- только `String` или примитивный тип
|
||||
- значение известно на этапе компиляции
|
||||
- только на верхнем уровне, в `object` или в `companion object`
|
||||
- нельзя у локальной переменной и нельзя с кастомным геттером
|
||||
|
||||
Значение подставляется в место использования на этапе компиляции (инлайнится), обращения к полю в рантайме нет.
|
||||
|
||||
```kotlin
|
||||
val runtime = computeLimit() // вычисляется при запуске
|
||||
const val compiled = 100 // подставлено компилятором
|
||||
```
|
||||
|
||||
## lateinit
|
||||
Для `var`, который точно будет проинициализирован, но не в момент объявления (DI, настройка в тестах):
|
||||
```kotlin
|
||||
class Service {
|
||||
lateinit var client: HttpClient
|
||||
|
||||
fun setup() {
|
||||
client = HttpClient()
|
||||
}
|
||||
|
||||
fun use() {
|
||||
if (::client.isInitialized) client.send()
|
||||
}
|
||||
}
|
||||
```
|
||||
Ограничения `lateinit`:
|
||||
- только `var`
|
||||
- тип не nullable
|
||||
- не примитивный тип (`Int`, `Double`, … запрещены)
|
||||
- нельзя у локальных переменных
|
||||
- нельзя с кастомным геттером/сеттером
|
||||
|
||||
Обращение до инициализации - `UninitializedPropertyAccessException`.
|
||||
|
||||
Альтернатива для ленивых вычислений - `by lazy`, он работает с `val`:
|
||||
```kotlin
|
||||
val config: Config by lazy { loadConfig() } // вычислится при первом обращении
|
||||
```
|
||||
Подробнее: [Свойства](../../ООП/Свойства.md)
|
||||
|
||||
## Области видимости
|
||||
```kotlin
|
||||
const val TOP = 1 // весь файл и, если public, другие файлы
|
||||
|
||||
fun demo() {
|
||||
val local = 2 // только тело функции
|
||||
if (local > 1) {
|
||||
val inner = 3 // только тело if
|
||||
}
|
||||
// println(inner) // ошибка: не видна
|
||||
}
|
||||
```
|
||||
Вложенная переменная может скрыть внешнюю - компилятор выдаст предупреждение `name shadowed`.
|
||||
|
||||
> [!info] Отличия от Java
|
||||
> | Java | Kotlin |
|
||||
> |---|---|
|
||||
> | `final int x = 1;` | `val x = 1` |
|
||||
> | `int x = 1;` | `var x = 1` |
|
||||
> | `var x = 1;` (только локально, с Java 10) | вывод типов везде, включая свойства класса |
|
||||
> | `static final int MAX = 100;` | `const val MAX = 100` |
|
||||
> | мутабельность по умолчанию | иммутабельность предпочтительна |
|
||||
> | `int x;` - значение по умолчанию 0 | неинициализированную переменную читать нельзя |
|
||||
>
|
||||
> Важное следствие: у свойств класса в Kotlin **нет значений по умолчанию**. В Java поле `int count;` автоматически 0, в Kotlin `var count: Int` без инициализатора не скомпилируется.
|
||||
>
|
||||
> Сравнить: [Переменные в Java](../../../Программирование%20на%20Java/Синтаксис%20и%20типы/Базовый%20синтаксис/Переменные.md)
|
||||
|
||||
> [!warning] Подводные камни
|
||||
> **`val` не делает объект неизменяемым** - см. пример с `MutableList` выше. Частая ошибка на собеседованиях.
|
||||
>
|
||||
> **`lateinit` прячет ошибку до рантайма.** Если забыли вызвать `setup()`, падение случится в момент использования, далеко от причины. Там, где можно, лучше конструктор или `by lazy`.
|
||||
>
|
||||
> **Вывод типов может дать не тот тип, что ожидали:**
|
||||
> ```kotlin
|
||||
> val x = 1 / 2 // 0, а не 0.5 — оба операнда Int
|
||||
> val y = 1.0 / 2 // 0.5
|
||||
> ```
|
||||
>
|
||||
> **`const val` зашивается в вызывающий код.** Если константа лежит в библиотеке и её значение изменилось, зависимый модуль нужно перекомпилировать - иначе он продолжит использовать старое значение.
|
||||
|
||||
Дополнительно: [Свойства](../../ООП/Свойства.md)
|
||||
Далее: [Операторы и выражения](Операторы%20и%20выражения.md)
|
||||
Reference in New Issue
Block a user