Распаковывающие объявления
Иногда удобно распаковать объект в ряд переменных, например:
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–2023 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/destructuring-declarations.html