Классы данных
Мы часто создаём классы, основное назначение которых — хранение данных. В таком классе стандартные функции и утилиты часто могут быть автоматически выведены из данных. В Kotlin это называется классом данных и отмечается как data.
data class User(val name: String, val age: Int)
Компилятор автоматически выводит следующие члены из всех свойств, объявленных в первичном конструкторе:
-
equals()/hashCode()пару; -
toString()вида"User(name=John, age=42)"; -
componentN()функции, соответствующие свойствам в порядке их объявления; -
copy()функцию (см. ниже).
Для обеспечения согласованности и осмысленного поведения генерируемого кода, классы данных должны удовлетворять следующим требованиям:
- Первичный конструктор должен иметь по крайней мере один параметр;
- Все параметры первичного конструктора должны быть помечены как
valилиvar; - Классы данных не могут быть абстрактными, открытыми, запечатанными или вложенными;
- (до версии 1.1) Классы данных могут реализовывать только интерфейсы.
Кроме того, генерация членов следует этим правилам относительно наследования членов:
- Если есть явные реализации
equals(),hashCode()илиtoString()в теле класса данных или final реализации в суперклассе, то эти функции не генерируются, и используются существующие реализации; - Если у супертипа есть
componentN()функции, которые являются open и возвращают совместимые типы, соответствующие функции генерируются для класса данных и переопределяют функции супертипа. Если функции супертипа не могут быть переопределены из-за несовместимых сигнатур или являются final, выводится ошибка; - Наследование класса данных от типа, у которого уже есть функция
copy(...)с соответствующей сигнатурой, устарело в Kotlin 1.2 и запрещено в Kotlin 1.3. - Явные реализации функций
componentN()иcopy()запрещены.
Начиная с версии 1.1, классы данных могут расширять другие классы (см. Запечатанные классы для примеров).
В JVM, если сгенерированный класс должен иметь конструктор без параметров, значения по умолчанию для всех свойств должны быть указаны (см. Конструкторы).
data class User(val name: String = "", val age: Int = 0)
Свойства, объявленные в теле класса
Обратите внимание, что компилятор использует только свойства, определённые внутри первичного конструктора, для автоматически генерируемых функций. Чтобы исключить свойство из сгенерированных реализаций, объявите его внутри тела класса:
data class Person(val name: String) {
var age: Int = 0
}
Только свойство name будет использовано внутри реализаций toString(), equals(), hashCode(), и copy(), и будет только одна функция-компонента component1(). Хотя у двух объектов Person могут быть разные возраста, они будут считаться равными.
data class Person(val name: String) {
var age: Int = 0
}
fun main() {
//sampleStart
val person1 = Person("John")
val person2 = Person("John")
person1.age = 10
person2.age = 20
//sampleEnd
println("person1 == person2: ${person1 == person2}")
println("person1 with age ${person1.age}: ${person1}")
println("person2 with age ${person2.age}: ${person2}")
}
Копирование
Часто требуется скопировать объект, изменив некоторые его свойства, но оставив остальные неизменными. Именно для этого генерируется функция copy(). Для класса User выше, её реализация будет следующей:
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
Это позволяет нам написать:
val jack = User(name = "Jack", age = 1) val olderJack = jack.copy(age = 2)
Классы данных и деструктурирующие объявления
Функции-компоненты, сгенерированные для классов данных, позволяют использовать их в деструктурирующих объявлениях:
val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age") // prints "Jane, 35 years of age"
Стандартные классы данных
Стандартная библиотека предоставляет Pair и Triple. Однако в большинстве случаев именованные классы данных — лучший выбор дизайна, потому что они делают код более читаемым, предоставляя осмысленные имена для свойств.
© 2010–2020 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/reference/data-classes.html