Destructuring declaration — це можливість Kotlin розкласти об'єкт на кілька змінних в одному виразі. Конструкція val (name, age) = user одночасно оголошує дві змінні, присвоюючи їм значення з компонентів об'єкта. За даними документації Kotlin (2026), деструктуризація скорочує обсяги коду під час роботи з data class на 30–50%. Destructuring declaration робить код більш лаконічним і читабельним.
Головне
Destructuring declaration (деструктуризуюче оголошення) — це синтаксична конструкція Kotlin, що дозволяє розкласти екземпляр класу на кілька змінних за один вираз. Ліва частина містить список змінних у дужках, права — об'єкт, що розкладається. Kotlin автоматично викликає для кожної змінної відповідну функцію componentN(), де N — порядковий номер змінної в дужках.
Найчастіше destructuring declaration застосовується з data class. Компілятор Kotlin автоматично генерує для data class функції component1(), component2() і так далі — за кількістю властивостей у первинному конструкторі. Для звичайних класів без модифікатора data componentN() не генеруються, але їх можна визначити вручну як операторні функції з ключовим словом operator.
Destructuring declaration стала популярним патерном завдяки своїй здатності спрощувати код під час роботи з колекціями пар, результатами функцій та обходом Map. Замість звернення person.firstName, person.lastName розробник пише val (firstName, lastName) = person. Це скорочує кількість рядків і підвищує читабельність, особливо в циклах і лямбдах.
При зустрічі з конструкцією val (a, b) = obj компілятор Kotlin генерує код: val a = obj.component1(); val b = obj.component2(). Якщо змінні оголошені з var, генеруються var-присвоєння. Тип кожної змінної виводиться з типу, що повертає відповідна функція componentN(). Це означає, що destructuring declaration повністю типобезпечна і перевіряється на етапі компіляції.
data class Person(val firstName: String, val lastName: String, val age: Int)
fun main() {
val person = Person("Alice", "Smith", 30)
// Деструктуризація: component1(), component2(), component3()
val (firstName, lastName, age) = person
println("$firstName $lastName, $age років")
}
У лістингу Person — data class із трьома властивостями. Kotlin генерує component1() → firstName, component2() → lastName, component3() → age. Вираз val (firstName, lastName, age) = person викликає ці функції та присвоює результати. Важливо: імена змінних можуть не збігатися з іменами властивостей — компілятор дивиться лише на порядок componentN() та їхні типи. Можна розкласти лише перші N властивостей, ігноруючи решту.
Data class — основний кандидат для destructuring declaration. Кожна data class автоматично отримує componentN() для всіх властивостей первинного конструктора. Порядок componentN() відповідає порядку оголошення властивостей. Це означає, що при зміні порядку полів у data class змінюється порядок змінних у деструктуризації — що може призвести до непомітних багів.
// Деструктуризація Pair
val pair = Pair("key", 42)
val (key, value) = pair
println("$key -> $value")
// Деструктуризація Triple
val triple = Triple("A", "B", "C")
val (first, second, third) = triple
// Map.Entry у циклі
val map = mapOf("a" to 1, "b" to 2)
for ((k, v) in map) {
println("$k = $v")
}
Pair і Triple — стандартні класи з готовою деструктуризацією на два і три компоненти. Pair часто використовується як тип, що повертають функції, яким потрібно повернути два пов'язані значення без створення окремої data class. У циклі for по Map.Entry конструкція (k, v) = entry деструктуризує ключ і значення через component1() і component2(). Це стандартний патерн обходу Map у Kotlin, що повністю замінює явні виклики key і value.
Якщо при деструктуризації деякі компоненти не потрібні, Kotlin дозволяє замінити їх на підкреслення _. Це покращує читабельність — читач одразу бачить, що компонент ігнорується. Крім того, використання _ запобігає випадковому зверненню до неініціалізованої змінної: компілятор не створює для _ жодної змінної, що усуває попередження про невикористовувані змінні.
data class Order(
val id: Long,
val customerName: String,
val amount: Double,
val status: String
)
fun process(orders: List<Order>) {
for ((id, _, amount) in orders) {
println("Замовлення $id: $amount")
}
}
У лістингу Order має чотири властивості, але в циклі потрібні лише id і amount. Підкреслення на місці customerName каже компілятору «пропусти component2()». Kotlin не викликає component2() і не створює змінної для цього компонента. Важливо: підкреслення можна використовувати лише в destructuring declaration, але не в data class-конструкторі. Якщо пропускається кілька компонентів підряд, кожному відповідає своє підкреслення.
Для класів без модифікатора data можна вручну визначити componentN(), додавши ключове слово operator. Це дозволяє використовувати destructuring declaration з будь-яким класом, включно зі сторонніми, для яких не можна змінити вихідний код — достатньо написати extension-функцію з operator. Такий підхід особливо корисний для бібліотечних класів і класів із Java-коду, у яких немає автоматичних componentN().
class Rect(val width: Int, val height: Int)
operator fun Rect.component1(): Int = width
operator fun Rect.component2(): Int = height
// Для Java-класу з геттерами
operator fun Dimension.component1(): Int = width
operator fun Dimension.component2(): Int = height
fun main() {
val rect = Rect(1920, 1080)
val (w, h) = rect
println("Роздільна здатність: ${w}x${h}")
}
У прикладі Rect — звичайний клас без data. Extension-функції з operator fun component1() = width і component2() = height додають підтримку деструктуризації. Аналогічно для java.awt.Dimension: operator extension на Dimension дозволяє розкласти його на width і height. Обмеження: максимальна кількість компонентів для destructuring declaration — 5. Теоретично можна визначити component6() і вище, але Kotlin не згенерує відповідний синтаксис для 6+ змінних у дужках.
Часті запитання
Так, кожна data class автоматично отримує componentN() для всіх властивостей первинного конструктора. Властивості, оголошені в тілі класу (через конструктор без val/var), не породжують componentN().
Якщо в val (a, b, c) = obj об'єкт має лише дві функції component, компілятор видасть помилку. Якщо змінних менше (val (a) = pair), Kotlin викличе лише component1() і проігнорує component2() — помилки не буде.
Так, Map.Entry підтримує деструктуризацію: val (key, value) = map.entries.first(). Для всієї Map одразу деструктуризація не працює — лише поелементно, у циклі for або через ітератор.
Так, Kotlin підтримує деструктуризацію в параметрах лямбди: map.forEach { (k, v) -> ... }. Для data class у параметрах лямбди потрібно додавати вкладені дужки навколо параметра.
Kotlin підтримує до 5 змінних у destructuring declaration. Якщо потрібно розкласти більше п'яти властивостей, об'єднайте їх у вкладені data class або використовуйте Pair/Triple всередині однієї змінної.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також