Встраиваемые классы-значения
Оборачивайте значения без дополнительных затрат
«Встраиваемые классы-значения» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Kotlin Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Kotlin Academy содержит 4 уроков всего.
Проблема обёртки
Обёртка примитивного типа в класс повышает типобезопасность, но обычно требует выделения памяти в куче. Классы-значения обеспечивают безопасность, а компилятор по возможности устраняет обёртку.
Объявление класса-значения
Отметьте класс @JvmInline value class ровно одним свойством в основном конструкторе. Он ведёт себя как отдельный тип.
@JvmInline
value class Password(val value: String)
fun main() {
val p = Password("secret")
println(p.value)
}Отдельный тип
В отличие от псевдонима типа, класс-значение является отдельным типом. Нельзя случайно передать обычный String там, где ожидается Password.
@JvmInline
value class Password(val value: String)
fun login(p: Password) = println("login with " + p.value)
fun main() {
login(Password("hunter2"))
}Нулевые накладные расходы
Во время выполнения компилятор обычно встраивает базовое значение, поэтому дополнительного выделения памяти под объект не происходит. В большинстве путей выполнения Password представлен обычным String.
@JvmInline
value class Meters(val amount: Double)
fun main() {
val d = Meters(5.0)
println(d.amount) // stored inline as a Double
}Методы и свойства
Классы-значения могут содержать функции и вычисляемые свойства, как и обычные классы.
@JvmInline
value class Celsius(val degrees: Double) {
fun toFahrenheit() = degrees * 9 / 5 + 32
}
fun main() {
println(Celsius(100.0).toFahrenheit())
}Блоки инициализации для проверки
Блок init позволяет проверить обёрнутое значение при создании, гарантируя, что каждый экземпляр корректен.
@JvmInline
value class Percentage(val value: Int) {
init {
require(value in 0..100) { "out of range" }
}
}
fun main() {
println(Percentage(75).value)
}Вычисляемые свойства
Можно добавлять вычисляемые свойства, получаемые из единственного хранимого значения, чтобы логика оставалась рядом с типом.
@JvmInline
value class Seconds(val value: Int) {
val asMinutes: Double get() = value / 60.0
}
fun main() {
println(Seconds(120).asMinutes)
}Реализация интерфейсов
Классы-значения могут реализовывать интерфейсы, что позволяет использовать их полиморфно. Обратите внимание: при обращении к ним как к типу интерфейса может потребоваться упаковка.
interface Describable {
fun describe(): String
}
@JvmInline
value class Money(val cents: Int) : Describable {
override fun describe() = "$" + cents / 100.0
}
fun main() {
println(Money(1599).describe())
}Когда происходит упаковка
Обёртка снова появляется при упаковке, когда значение используется как допускающее отсутствие значения, как интерфейс или в обобщённой коллекции. В таких случаях компилятор создаёт настоящий объект — это по-прежнему корректно, но менее эффективно.
@JvmInline
value class Id(val raw: Int)
fun main() {
val direct = Id(1) // inlined
val boxed: Id? = Id(2) // boxed because nullable
println("" + direct.raw + " " + boxed?.raw)
}Класс-значение и класс данных
data class всегда требует выделения памяти и может содержать несколько свойств. value class содержит ровно одно свойство и рассчитан на нулевые накладные расходы. Выбирайте классы-значения для тонких типобезопасных обёрток над единственным значением.
Почему это важно
Классы-значения позволяют:
- Не допускать путаницы между параметрами одинакового типа
- Привязывать проверку к примитивному значению
- Обычно не платить за это во время выполнения
Это типобезопасное решение там, где псевдонимов недостаточно.
Быстрая проверка
Проверьте, насколько хорошо Вы понимаете встраиваемые классы-значения.
Итоги
Вы изучили встраиваемые классы-значения:
- Объявляются с помощью
@JvmInline value classи содержат одно свойство - Являются отдельным типом с обычно нулевыми накладными расходами
- Поддерживают методы, вычисляемые свойства и проверку в
init - Упаковка происходит при использовании значения в допускающем отсутствие значения, обобщённом или интерфейсном контексте
Далее: практические варианты использования.
Часто задаваемые вопросы
Урок «Встраиваемые классы-значения» бесплатный?
Да — полный текст урока «Встраиваемые классы-значения» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Kotlin Academy, подпишись на CoddyKit PRO. Курс Kotlin Academy содержит 4 уроков всего.
Чему я научусь в уроке «Встраиваемые классы-значения»?
Оборачивайте значения без дополнительных затрат Ты практикуешь Kotlin Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Kotlin Academy?
Предыдущий опыт не требуется. Kotlin Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Встраиваемые классы-значения»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Kotlin Academy?
Да. Каждый урок Kotlin Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Псевдонимы типов
- Встраиваемые классы-значения
- Варианты использования
- Ограничения