Объекты данных  —  это новый функционал, представленный в Kotlin 1.7.20 и планируемый к выпуску в версии 1.9. Разберемся, для чего он нужен.

Какую проблему призваны решить объекты данных?

Ниже, в типичном примере иерархии запечатанных классов, используется sealed interface (мог быть и sealed class), которым определяются возможные состояния экрана профиля: data class для состояния успеха, а object для состояний ошибки и загрузки.

sealed interface ProfileScreenState {
data class Success(val username: String): ProfileScreenState
object Error: ProfileScreenState
object Loading: ProfileScreenState
}

А что если нужно занести в журнал или распечатать текущее состояние экрана для отладки либо отправки в службу аналитики? В строковом представлении класса данных ProfileScreenState.Success как раз содержатся имя класса и все его свойства.

Но если в Kotlin вывести обычное объявление object, получим строку с полным именем пакета, именем объекта и адресом, где этот объект хранится в памяти. Поскольку объекты в Kotlin  —  синглтоны, при каждом выводе этого объекта адресная часть останется неизменной и для нас нерелевантной:

com.dataobjects.example.ProfileScreenState$Loading@6d03e736
Success(username=exampleUser1)
com.dataobjects.example.ProfileScreenState$Error@5fd0d5ae

Одно из решений  —  на каждом объекте реализации переопределить функцию toString(): String:

sealed interface ProfileScreenState {
data class Success(val username: String) : ProfileScreenState

object Error : ProfileScreenState {
override fun toString(): String = "Error"
}

object Loading : ProfileScreenState {
override fun toString(): String = "Loading"
}
}

Не слишком ли много шаблонного кода для такой тривиальной задачи?

Объекты данных

В Kotlin эту проблему планируют решить с помощью объектов данных. data object  —  это обычный object, но с реализацией по умолчанию функции toString(), которая выводит его имя без ручного ее переопределения и с соответствием поведения определению data class. Соответствие поведения классам данных особенно актуально для иерархий запечатанных классов.

Сейчас объекты данных  —  это экспериментальный функционал. Чтобы его опробовать, указываем компилятору версию Kotlin 1.9:

kotlinOptions.languageVersion = "1.9"

Синхронизировав проект, получаем в имеющихся объектах  —  части запечатанной иерархии  —  предложение преобразовать их в data object:

Предложение интегрированной среды разработки  —  преобразовать в объект данных запечатанный подобъект
Предложение интегрированной среды разработки  —  преобразовать в объект данных объект с переопределенной функцией toString

После применения предложения объекты преобразуются в data object:

sealed interface ProfileScreenState {
data class Success(val username: String) : ProfileScreenState
data object Error : ProfileScreenState
data object Loading : ProfileScreenState
}

Выводим их и видим, что строковое представление теперь похоже на data class и выводится только имя объекта:

Loading
Success(username=exampleUser1)
Error

Заключение

Объекты данных  —  это новый функционал Kotlin, который улучшает строковое представление object. Он особенно актуален, когда имеются иерархии запечатанных классов с другими классами данных и их нужно занести в журнал или распечатать для отладки или аналитики.

Обратите внимание: на момент написания этой статьи объекты данных  —  экспериментальный функционал Kotlin. В будущем их определение может измениться.

Подробнее об объектах данных Kotlin см. в:

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Domen Lanišnik: Data Objects in Kotlin

Предыдущая статьяКласс данных в Kotlin
Следующая статьяЗапускаем Rocket REST API на AWS