Ответ
Sealed class позволяет ограничить иерархию наследования. Её наследниками могут быть только классы, объявленные в том же файле или вложенные классы (включая data, object и обычные классы).
Пример:
sealed class Result {
data class Success(val data: String) : Result()
data class Error(val message: String) : Result()
object Loading : Result()
}
Ключевые ограничения:
- Наследники должны быть объявлены в том же файле.
- Можно использовать data class, object или обычные классы.
- В Kotlin 1.5+ разрешены наследники в разных файлах, но в одном модуле (с модификатором
sealed).
Ответ 18+ 🔞
А, sealed class! Ну это вообще огонь тема, если честно. Представь себе, что у тебя есть сущность, и ты заранее знаешь, какие у неё могут быть состояния или варианты. И ты хочешь, чтобы больше никто на стороне не мог придумать какой-нибудь левый, ебанько, наследничек. Вот sealed class — это как раз такая хитрая жопа, которая говорит: "Всё, ребята, наследники — только вот эти, которые я тут рядом перечислил, и точка".
Раньше, ёпта, вообще строго было: все наследники должны были быть в одном файле. Прям сидели, как в казарме, не высовывались. Сейчас, в новых версиях, расслабились немного — можно в одном модуле, но тоже с приставкой sealed. Но классика — это когда всё в одном месте, и тогда компилятор просто в рот мне чих-пых, он умный становится. Он видит все возможные варианты и в when может не требовать else ветки, потому что он точно знает, что других вариантов быть не может. Удобно же, волнение ебать!
Вот смотри на примере, тут всё понятно становится:
sealed class Result {
data class Success(val data: String) : Result()
data class Error(val message: String) : Result()
object Loading : Result()
}
Вот и вся иерархия. Result — это sealed class. У него три законных отпрыска: Success, Error и Loading. Success и Error — data classы, удобно для хранения инфы. Loading — это просто object, синглтон, потому что состояние одно на всех, зачем плодить сущности.
И теперь, когда ты это пишешь в коде:
fun handleResult(result: Result) {
when (result) {
is Result.Success -> println("Ура! Данные: ${result.data}")
is Result.Error -> println("Ошибка: ${result.message}")
Result.Loading -> println("Грузимся...")
}
// else не нужен! Компилятор сам понимает, что варианты исчерпаны.
}
Красота же? Никаких неожиданностей. Если ты вдруг добавишь в sealed class новый тип, компилятор сразу начнёт ругаться на все when по этому классу, которые стали неполными. Защита от распиздяев, которые забывают про новые кейсы. В общем, штука мощная, для моделирования состояний — просто пизда рулю.