Spec-Zone.ru › Kotlin 2

Деструктурирующие объявления

Иногда удобно деструктурировать объект на несколько переменных, например:

val (name, age) = person 

Этот синтаксис называется деструктурирующим объявлением. Деструктурирующее объявление создает несколько переменных одновременно. Вы объявили две новые переменные: name и age, которые можно использовать независимо:

println(name)
println(age)

Деструктурирующее объявление компилируется в следующий код:

val name = person.component1()
val age = person.component2()

Функции component1() и component2() — еще один пример принципа соглашений, широко используемого в Kotlin (см. операторы + и *, а также циклы for). Справа от деструктурирующего объявления может находиться что угодно, если для этого объекта можно вызвать необходимое количество функций-компонентов. И, конечно, могут быть component3(), component4() и так далее.

Для использования в деструктурирующем объявлении функции componentN() необходимо пометить ключевым словом operator.

Деструктурирующие объявления также работают в циклах for:

for ((a, b) in collection) { ... }

Переменные a и b получают значения, возвращаемые функциями component1() и component2(), вызванными для элементов коллекции.

Пример: возврат двух значений из функции

Предположим, что из функции нужно вернуть два значения — например, объект с результатом и некоторый статус. Компактный способ сделать это в Kotlin — объявить класс данных и вернуть его экземпляр:

data class Result(val result: Int, val status: Status)
fun function(...): Result {
    // computations
    
    return Result(result, status)
}

// Now, to use this function:
val (result, status) = function(...)

Поскольку в классах данных автоматически объявляются функции componentN(), здесь работают деструктурирующие объявления.

Можно также использовать стандартный класс Pair и возвращать из function() значение Pair<Int, Status>, но обычно лучше давать данным подходящие имена.

Пример: деструктурирующие объявления и отображения

Пожалуй, самый удобный способ перебрать отображение выглядит так:

for ((key, value) in map) {
   // do something with the key and the value
}

Чтобы это работало, нужно

  • представить отображение в виде последовательности значений, предоставив функцию iterator().

  • представить каждый элемент в виде пары, предоставив функции component1() и component2().

Стандартная библиотека действительно предоставляет такие расширения:

operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = entrySet().iterator()
operator fun <K, V> Map.Entry<K, V>.component1() = getKey()
operator fun <K, V> Map.Entry<K, V>.component2() = getValue()

Поэтому вы можете свободно использовать деструктурирующие объявления в циклах for с отображениями (а также с коллекциями экземпляров классов данных и других подобных объектов).

Подчеркивание для неиспользуемых переменных

Если переменная в деструктурирующем объявлении вам не нужна, вместо ее имени можно поставить подчеркивание:

val (_, status) = getResult()

Для пропущенных таким образом компонентов функции-операторы componentN() не вызываются.

Деструктуризация в лямбдах

Синтаксис деструктурирующих объявлений можно использовать для параметров лямбды. Если у лямбды есть параметр типа Pair (или Map.Entry, или любого другого типа с соответствующими функциями componentN), можно объявить несколько новых параметров вместо одного, заключив их в круглые скобки:

map.mapValues { entry -> "${entry.value}!" }
map.mapValues { (key, value) -> "$value!" }

Обратите внимание на разницу между объявлением двух параметров и объявлением деструктурируемой пары вместо одного параметра:

{ a -> ... } // one parameter
{ a, b -> ... } // two parameters
{ (a, b) -> ... } // a destructured pair
{ (a, b), c -> ... } // a destructured pair and another parameter

Если какой-либо компонент деструктурируемого параметра не используется, его можно заменить подчеркиванием, чтобы не придумывать для него имя:

map.mapValues { (_, value) -> "$value!" }

Можно указать тип всего деструктурируемого параметра или отдельно тип конкретного компонента:

map.mapValues { (_, value): Map.Entry<Int, String> -> "$value!" }

map.mapValues { (_, value: String) -> "$value!" }

Деструктуризация по именам

Kotlin поддерживает деструктурирующие объявления по именам, в которых переменные сопоставляются со свойствами по имени, а не по позиции, как в позиционной деструктуризации, определяемой функциями componentN().

Дополнительную информацию о деструктуризации по именам см. в KEEP этой возможности.

При позиционной деструктуризации переменные соответствуют порядку функций componentN(), например:

data class User(val username: String, val email: String)

fun main() {
    val user = User("alice", "alice@example.com")

    val (email, username) = user

    println(email)
    // alice

    println(username)
    // alice@example.com
}

В этом примере деструктуризация зависит от порядка функций componentN(), поэтому email получает значение username, а username — значение email.

При деструктуризации по именам извлекаемые значения определяются именами свойств, а не позицией функций componentN():

fun main() {
    val user = User("alice", "alice@example.com")

    // Uses name-based destructuring with explicit form
    (val mail = email, val name = username) = user

    println(name)
    // alice

    println(mail)
    // alice@example.com
}

Деструктуризация по именам имеет статус экспериментальной. При включении этой возможности также вводится новый синтаксис позиционной деструктуризации с квадратными скобками. Используйте этот синтаксис для типов, в которых важен порядок элементов, например списков и других упорядоченных коллекций, а также безымянных кортежей, таких как Pair или Triple:

val point = Pair(10, 20)

// Uses position-based destructuring
val [x, y] = point

Управлять интерпретацией деструктурирующих объявлений компилятором можно с помощью параметра компилятора -Xname-based-destructuring.

У него есть следующие режимы:

  • only-syntax включает явную форму деструктуризации по именам, не изменяя поведение существующих деструктурирующих объявлений.

  • name-mismatch выводит предупреждения, если при позиционной деструктуризации классов данных используются имена переменных, не совпадающие с именами свойств.

  • complete включает краткую форму деструктуризации по именам с круглыми скобками и сохраняет поддержку позиционной деструктуризации с синтаксисом квадратных скобок.

Перед включением режима complete изучите предупреждения, выведенные в режиме name-mismatch, и устраните их. Эти предупреждения показывают, какие деструктурирующие объявления компилятор интерпретирует иначе в режиме complete, а также содержат рекомендации по их соответствующему переписыванию.

В режиме complete краткий синтаксис деструктуризации с круглыми скобками сопоставляет переменные именам свойств, а не их позициям:

val (email, username) = user

Чтобы включить деструктуризацию по именам в проекте, добавьте параметр компилятора в файл конфигурации сборки:

kotlin {
    compilerOptions {
        freeCompilerArgs.add("-Xname-based-destructuring=only-syntax")
    }
}
<build>
    <plugins>
        <plugin>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-maven-plugin</artifactId>
            <configuration>
                <args>
                    <arg>-Xname-based-destructuring=only-syntax</arg>
                </args>
            </configuration>
        </plugin>
    </plugins>
</build>
24 марта 2026 г.
РефлексияРазработка серверной части на Kotlin

© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/destructuring-declarations.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API