← Назад к вопросам

Может ли Sealed Class наследовать Sealed Class?

2.2 Middle🔥 111 комментариев
#Kotlin основы#Архитектура и паттерны

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Вопрос о наследовании Sealed Class

Да, sealed class может наследовать от другой sealed class в Kotlin. Это один из важных аспектов системы типов Kotlin, который позволяет создавать более сложные иерархии ограниченных классов.

Ключевые правила и особенности

  • Наследование разрешено: Класс, объявленный как sealed, может быть подклассом другого sealed class. Это позволяет строить иерархии с несколькими уровнями абстракции.
  • Все подклассы должны быть известны: Основное правило sealed class остается неизменным — все прямые подклассы должны быть объявлены в том же файле или в том же модуле (с некоторыми исключениями в последних версиях Kotlin). Это правило распространяется и на наследников.
  • Наследование от open или abstract классов: Sealed class также может наследоваться от обычного open или abstract класса, но сам по себе является abstract по умолчанию и не может быть инстанциирован напрямую.

Пример иерархии с наследованием

Рассмотрим практический пример, где у нас есть базовый sealed class для представления результатов операции, и более специализированный sealed class, наследующий от него.

// Базовый sealed class для результата
sealed class OperationResult {
    data class Success(val message: String) : OperationResult()
    data class Error(val code: Int, val description: String) : OperationResult()
}

// Sealed class, наследующий OperationResult, для более конкретных результатов сети
sealed class NetworkResult : OperationResult() {
    data class HttpError(val statusCode: Int) : NetworkResult()
    data class Timeout(val duration: Long) : NetworkResult()
    // Можно также использовать родительские типы внутри этой иерархии
    object UnknownError : NetworkResult()
}

Использование в условиях when

При использовании в выражении when, которое должно быть exhaustive (полным) для sealed class, необходимо учитывать все подклассы на всех уровнях иерархии.

fun handleResult(result: OperationResult) {
    when (result) {
        is OperationResult.Success -> println("Success: ${result.message}")
        is OperationResult.Error -> println("Error: ${result.code}")
        // Без этих веток компилятор выдаст ошибку, так как NetworkResult является подклассом OperationResult
        is NetworkResult.HttpError -> println("HTTP Error: ${result.statusCode}")
        is NetworkResult.Timeout -> println("Timeout after ${result.duration}ms")
        is NetworkResult.UnknownError -> println("Unknown network error")
    }
}

Важные технические детали

  1. Модификатор sealed: При наследовании sealed class от другого sealed class, подкласс также должен быть объявлен с модификатором sealed. Если подкласс объявлен как open или data class, он нарушает правило "все подклассы известны" для родительского класса.
  2. Расположение в файле: Все прямые подклассы sealed class (включая другие sealed classes) должны быть объявлены в одном файле. Однако, начиная с Kotlin 1.5, появилась возможность объявлять подклассы в разных файлах того же модуля, если используется экспериментальная функция.
  3. Иерархия с несколькими уровнями: Можно создавать глубокие иерархии, например, sealed class A -> sealed class B -> data class C. Это полезно для моделирования сложных доменных моделей с четкими ограничениями.

Преимущества такого подхода

  • Более точное моделирование: Позволяет отразить реальные отношения в доменной области, где есть общие категории и более специфичные подкатегории.
  • Безопасность типов: Компилятор гарантирует, что все возможные варианты учтены в выражениях when, даже при сложных иерархиях.
  • Читаемость кода: Иерархия классов становится более организованной и интуитивно понятной.

Таким образом, наследование sealed class от другого sealed class — это мощный инструмент в Kotlin, который расширяет возможности создания безопасных и выразительных иерархий типов.