Destructuring declaration — to możliwość Kotlina, aby rozłożyć obiekt na kilka zmiennych w jednym wyrażeniu. Konstrukcja val (name, age) = user jednocześnie deklaruje dwie zmienne, przypisując im wartości z komponentów obiektu. Według dokumentacji Kotlina (2026), destrukturyzacja zmniejsza ilość kodu przy pracy z data class o 30–50%. Destructuring declaration sprawia, że kod jest bardziej zwięzły i czytelny.
Najważniejsze
Destructuring declaration (deklaracja destrukturyzująca) — to konstrukcja składniowa Kotlina, pozwalająca rozłożyć instancję klasy na kilka zmiennych w jednym wyrażeniu. Lewa strona zawiera listę zmiennych w nawiasach, prawa — rozkładany obiekt. Kotlin automatycznie wywołuje dla każdej zmiennej odpowiednią funkcję componentN(), gdzie N to numer porządkowy zmiennej w nawiasach.
Najczęściej destructuring declaration jest stosowana z data class. Kompilator Kotlina automatycznie generuje dla data class funkcje component1(), component2() i tak dalej — według liczby właściwości w konstruktorze pierwotnym. Dla zwykłych klas bez modyfikatora data componentN() nie są generowane, ale można je zdefiniować ręcznie jako funkcje operatorowe z kluczowym słowem operator.
Destructuring declaration stała się popularnym wzorcem dzięki swojej zdolności do upraszczania kodu podczas pracy z kolekcjami par, wynikami funkcji i przeglądaniem Map. Zamiast odwołania person.firstName, person.lastName programista pisze val (firstName, lastName) = person. Zmniejsza to liczbę wierszy i zwiększa czytelność, szczególnie w pętlach i lambdach.
Przy napotkaniu konstrukcji val (a, b) = obj kompilator Kotlina generuje kod: val a = obj.component1(); val b = obj.component2(). Jeśli zmienne są zadeklarowane z var, generowane są przypisania var. Typ każdej zmiennej jest wnioskowany z typu zwracanego odpowiedniej funkcji componentN(). Oznacza to, że destructuring declaration jest w pełni bezpieczna typowo i sprawdzana na etapie kompilacji.
data class Person(val firstName: String, val lastName: String, val age: Int)
fun main() {
val person = Person("Alice", "Smith", 30)
// Destrukturyzacja: component1(), component2(), component3()
val (firstName, lastName, age) = person
println("$firstName $lastName, $age lat")
}
W listingu Person — data class z trzema właściwościami. Kotlin generuje component1() → firstName, component2() → lastName, component3() → age. Wyrażenie val (firstName, lastName, age) = person wywołuje te funkcje i przypisuje wyniki. Ważne: nazwy zmiennych mogą nie pokrywać się z nazwami właściwości — kompilator patrzy tylko na kolejność componentN() i ich typy. Można rozłożyć tylko pierwsze N właściwości, ignorując pozostałe.
Data class — główny kandydat dla destructuring declaration. Każdy data class automatycznie otrzymuje componentN() dla wszystkich właściwości konstruktora pierwotnego. Kolejność componentN() odpowiada kolejności deklaracji właściwości. Oznacza to, że przy zmianie kolejności pól w data class zmienia się kolejność zmiennych w destrukturyzacji — co może prowadzić do niezauważalnych błędów.
// Destrukturyzacja Pair
val pair = Pair("key", 42)
val (key, value) = pair
println("$key -> $value")
// Destrukturyzacja Triple
val triple = Triple("A", "B", "C")
val (first, second, third) = triple
// Map.Entry w pętli
val map = mapOf("a" to 1, "b" to 2)
for ((k, v) in map) {
println("$k = $v")
}
Pair i Triple — standardowe klasy z gotową destrukturyzacją na dwa i trzy komponenty. Pair jest często używany jako typ zwracany funkcji, które muszą zwrócić dwie powiązane wartości bez tworzenia osobnego data class. W pętli for po Map.Entry konstrukcja (k, v) = entry destrukturyzuje klucz i wartość przez component1() i component2(). Jest to standardowy wzorzec przeglądania Map w Kotlin, całkowicie zastępujący jawne wywołania key i value.
Jeśli przy destrukturyzacji niektóre komponenty nie są potrzebne, Kotlin pozwala zastąpić je podkreśleniem _. Poprawia to czytelność — czytelnik od razu widzi, że komponent jest ignorowany. Ponadto użycie _ zapobiega przypadkowemu odwołaniu się do niezainicjalizowanej zmiennej: kompilator nie tworzy dla _ żadnej zmiennej, co eliminuje ostrzeżenia o nieużywanych zmiennych.
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("Zamówienie $id: $amount")
}
}
W listingu Order ma cztery właściwości, ale w pętli potrzebne są tylko id i amount. Podkreślenie w miejscu customerName mówi kompilatorowi „pomiń component2()". Kotlin nie wywołuje component2() i nie tworzy zmiennej dla tego komponentu. Ważne: podkreślenia można używać tylko w destructuring declaration, ale nie w konstruktorze data class. Jeśli pomijanych jest kilka komponentów z rzędu, każdemu odpowiada własne podkreślenie.
Dla klas bez modyfikatora data można ręcznie zdefiniować componentN(), dodając kluczowe słowo operator. Pozwala to używać destructuring declaration z dowolną klasą, w tym zewnętrznymi, dla których nie można zmienić kodu źródłowego — wystarczy napisać funkcję rozszerzającą z operatorem. Takie podejście jest szczególnie przydatne dla klas bibliotecznych i klas z kodu Java, które nie mają automatycznych componentN().
class Rect(val width: Int, val height: Int)
operator fun Rect.component1(): Int = width
operator fun Rect.component2(): Int = height
// Dla klasy Java z getterami
operator fun Dimension.component1(): Int = width
operator fun Dimension.component2(): Int = height
fun main() {
val rect = Rect(1920, 1080)
val (w, h) = rect
println("Rozdzielczość: ${w}x${h}")
}
W przykładzie Rect — zwykła klasa bez data. Funkcje rozszerzające z operator fun component1() = width i component2() = height dodają obsługę destrukturyzacji. Podobnie dla java.awt.Dimension: operator rozszerzający na Dimension pozwala rozłożyć go na width i height. Ograniczenie: maksymalna liczba komponentów dla destructuring declaration — 5. W teorii można zdefiniować component6() i wyższe, ale Kotlin nie wygeneruje odpowiedniej składni dla 6+ zmiennych w nawiasach.
Często zadawane pytania
Tak, każdy data class automatycznie otrzymuje componentN() dla wszystkich właściwości konstruktora pierwotnego. Właściwości zadeklarowane w ciele klasy (przez konstruktor bez val/var) nie generują componentN().
Jeśli w val (a, b, c) = obj obiekt ma tylko dwie funkcje component, kompilator zgłosi błąd. Jeśli zmiennych jest mniej (val (a) = pair), Kotlin wywoła tylko component1() i zignoruje component2() — błąd nie wystąpi.
Tak, Map.Entry obsługuje destrukturyzację: val (key, value) = map.entries.first(). Dla całej Map naraz destrukturyzacja nie działa — tylko element po elemencie, w pętli for lub przez iterator.
Tak, Kotlin obsługuje destrukturyzację w parametrach lambdy: map.forEach { (k, v) -> ... }. Dla data class w parametrach lambdy należy dodać zagnieżdżone nawiasy wokół parametru.
Kotlin obsługuje do 5 zmiennych w destructuring declaration. Jeśli trzeba rozłożyć więcej niż pięć właściwości, połącz je w zagnieżdżone data class lub użyj Pair/Triple wewnątrz jednej zmiennej.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również