| type | doc |
|---|---|
| layout | reference |
| category | Other |
| title | Мульти-декларации |
| url | https://kotlinlang.ru/docs/reference/multi-declarations.html |
Иногда удобно деструктуризировать объект на несколько переменных, например:
val (name, age) = person Этот синтаксис называется деструктуризирующее присваивание. Он позволяет присвоить объект сразу нескольким
переменным, разбив его на части. Мы объявили две переменные: name и age, и теперь можем использовать их по отдельности:
println(name)
println(age)Эта декларация транслируется в такой код:
val name = person.component1()
val age = person.component2()Как и многое другое в Kotlin, мульти-декларации опираются на конвенцию: функции componentN() вызываются по имени,
то есть могут быть объявлены как в классе person, так и вне его — в качестве расширений.
Заметьте, что функции componentN() нужно отмечать ключевым словом operator, чтобы позволить их использование в деструктуризирующем присваивании.
Деструктуризирующие присваивания также работают в циклах for:
for ((a, b) in collection) { ... }В данном примере значения переменных a и b возращены методами component1() и component2(), вызванными неявно у элементов коллекции.
Предположим, нам нужно вернуть два значения из функции. Например, результат вычисления и какой-нибудь статус.
Компактный способ достичь этого — объявление data-класса и возвращение его экземпляра:
data class Result(val result: Int, val status: Status)
fun function(...): Result {
// вычисления
return Result(result, status)
}
// Теперь мы можем использовать деструктуризирующее присваивание:
val (result, status) = function(...)Так как data-классы автоматически объявляют componentN()-функции, мульти-декларации будут работать с ними "из коробки".
ПРИМЕЧАНИЕ: мы также могли использовать стандартный класс Pair, чтобы заставить функцию вернуть 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-классов).