Распаковки объявлений
Иногда удобно распаковать объект на несколько переменных, например:
val (name, age) = person
Этот синтаксис называется распаковкой объявления. Объявление распаковки создаёт сразу несколько переменных. Вы объявили две новые переменные: name и age, и можете использовать их независимо:
println(name) println(age)
Объявление распаковки компилируется в следующий код:
val name = person.component1() val age = person.component2()
Функции component1() и component2() — это ещё один пример принципа соглашений, широко используемого в Kotlin (см. операторы, такие как + и *, for-циклы в качестве примера). Всё может находиться справа от объявления распаковки, если на него можно вызвать необходимое количество компонентных функций. И, конечно же, могут быть component3() и component4() и так далее.
Объявления распаковки также работают в 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() функции, объявления распаковки работают здесь.
Пример: объявления распаковки и карты
Вероятно, самый удобный способ пройти по карте — это:
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!" }
© 2010–2022 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/destructuring-declarations.html