type | layout | category | title | url |
---|---|---|---|---|
doc |
reference |
Other |
Мульти-декларации |
Иногда удобно деструктуризировать объект на несколько переменных, например:
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
-классов).