Распаковка объявлений
Иногда удобно распаковать объект на несколько переменных, например:
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 и возврат его экземпляра:
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(...)
Так как data classes автоматически объявляют функции 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 с картами (а также коллекциями экземпляров data class и т. д.).
Подчёркивание для неиспользуемых переменных (с версии 1.1)
Если вам не нужна переменная в объявлении распаковки, вы можете поместить подчёркивание вместо её имени:
val (_, status) = getResult()
Функции операторов componentN() не вызываются для компонентов, которые пропущены таким образом.
Распаковка в лямбдах (с версии 1.1)
Вы можете использовать синтаксис объявлений распаковки для параметров лямбда. Если у лямбда есть параметр типа 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–2020 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/reference/multi-declarations.html