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

Можно ли в операторе when указать не всех наследников sealed класса?

1.0 Junior🔥 122 комментариев
#Kotlin основы

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

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

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

Можно ли в операторе when указать не всех наследников sealed класса?

Да, в операторе when можно указать не всех наследников sealed класса, но это требует явного указания компилятору, как обрабатывать неохваченные случаи. По умолчанию, при использовании when в качестве выражения (то есть когда оно возвращает значение) и работе с sealed классом, компилятор Kotlin требует покрыть все возможные варианты (все наследники). Если покрыты не все случаи, компиляция завершится ошибкой. Однако есть несколько способов обойти это требование.

Когда when является выражением (expression)

Если when используется как выражение (например, результат присваивается переменной или возвращается из функции), компилятор проверяет полноту покрытия. Пример:

sealed class Result {
    data class Success(val data: String) : Result()
    data class Error(val message: String) : Result()
    object Loading : Result()
}

fun handleResult(result: Result): String {
    return when (result) { // when является выражением (возвращает String)
        is Result.Success -> "Данные: ${result.data}"
        is Result.Error -> "Ошибка: ${result.message}"
        Result.Loading -> "Загрузка..."
        // Если убрать одну ветку, например, Result.Loading, компилятор выдаст ошибку:
        // 'when' expression must be exhaustive, add necessary 'is Loading' branch or 'else' branch instead.
    }
}

Как указать не всех наследников

Чтобы покрыть не все случаи, можно использовать следующие подходы:

  1. Добавить ветку else
    Ветка else обрабатывает все неупомянутые наследники. Это делает when исчерпывающим, но теряется безопасность типов, так как else может скрыть необработанный случай.

    fun handleResultPartial(result: Result): String {
        return when (result) {
            is Result.Success -> "Данные: ${result.data}"
            else -> "Не success" // Обрабатывает Result.Error и Result.Loading
        }
    }
    
  2. Использовать when как оператор (statement)
    Если when используется как оператор (не возвращает значение), компилятор не требует полноты покрытия. Но это может привести к логическим ошибкам, если какой-то случай не обработан.

    fun logResult(result: Result) {
        when (result) { // when является оператором, можно указать только нужные ветки
            is Result.Success -> println("Успех: ${result.data}")
            is Result.Error -> println("Ошибка: ${result.message}")
            // Result.Loading не обрабатывается, но компилятор не выдаст ошибку
        }
    }
    
  3. Использовать sealed класс с нефинальными ветками
    Если наследник sealed класса сам является open или sealed, компилятор не может гарантировать полноту, так как могут быть подклассы. Но это более сложный сценарий.

Рекомендации

  • Всегда старайтесь покрывать все случаи в when-выражениях. Это обеспечивает безопасность типов и предотвращает ошибки в рантайме.
  • Избегайте else при работе с sealed классами, если только это не оправдано (например, для обработки заведомо известных невариантов). Использование else снижает преимущества sealed классов.
  • Для частичной обработки используйте when как оператор, но добавьте комментарии или логирование для необработанных случаев, чтобы избежать молчаливого пропуска важной логики.

Пример с else (не рекомендуется без необходимости)

fun getStatus(result: Result): String {
    return when (result) {
        is Result.Success -> "OK"
        else -> "Not OK" // Потенциально скрывает детали (Error vs Loading)
    }
}

Вывод: Указать не всех наследников sealed класса в when можно, но это требует осторожности. Полнота покрытия — это ключевое преимущество sealed классов в Kotlin, поэтому отклоняться от этого стоит лишь в особых случаях, осознавая последствия.