Что такое деструктуризация в Kotlin и как она работает
Что проверяют
Знаете ли вы, во что компилируется val (a, b) = x, и понимаете ли, что деструктуризация в Kotlin позиционная. Следом обычно спрашивают, как сделать её для своего класса и чем она опасна при рефакторинге.
Как отвечать
Деструктурирующее объявление это синтаксический сахар над componentN(). Строка val (name, age) = user превращается в val name = user.component1() и val age = user.component2(). Лишних объектов нет, только столько вызовов, сколько переменных.
Откуда берутся componentN():
data class: компилятор генерирует их для свойств основного конструктора в порядке объявления;- свой класс: достаточно объявить
operator fun component1(), в том числе расширением для чужого класса; - стандартная библиотека:
Pair,Triple,Map.Entry, а дляListи массивов расширения сcomponent1()поcomponent5().
Где применяется: локальные переменные, цикл for ((key, value) in map), параметры лямбды map.forEach { (key, value) -> }, возврат двух значений через Pair или маленький data class. Ненужную позицию заменяют на _, и её componentN() не вызывается. Свойства класса так объявить нельзя, только локальный код.
Из Android хорошо показать Compose: val (text, setText) = remember { mutableStateOf("") } работает, потому что MutableState объявляет component1() для значения и component2() для сеттера. Ещё пример: разбор UiState из ViewModel на пару полей прямо в функции рендера.
Где спотыкаются
Не понимают, что порядок решает всё. Поменяйте местами в data class два свойства одного типа, например firstName и lastName, и каждая деструктуризация в проекте молча начнёт путать значения, а компилятор промолчит.
Деструктурируют List неизвестной длины. val (a, b, c) = list на списке из двух элементов падает с IndexOutOfBoundsException, потому что component3() это просто get(2).
Пытаются разложить обычный класс или раскладывают data class на восемь переменных. В первом случае нет componentN() и код не скомпилируется, во втором он читается хуже, чем обращение по именам.