В ранних версиях Kotlin для ограничения иерархии типов использовались sealed классы, которые позволяли разработчикам явно контролировать допустимые подтипы посредством ограничения объявления наследников только внутри одного файла. Для некоторых задач этого было недостаточно, особенно когда требовалось описать схожие иерархии с помощью интерфейсов. Для решения этой проблемы, начиная с Kotlin 1.5, был введён модификатор sealed для интерфейсов.
Обычные интерфейсы позволяют реализовывать их в любом месте проекта, что часто мешает обеспечивать абсолютную закрытость иерархии типов и использовать исчерпывающие проверки типов (exhaustive when). Это может привести к ошибкам в рантайме, невозможности статически проверить все варианты.
Sealed интерфейсы позволяют ограничить список классов-реализаций в рамках одного файла, повысив предсказуемость системы типов и безопасность сопоставления с образцом (pattern matching).
sealed interface NetworkResult class Success(val data: String): NetworkResult class Failure(val error: Throwable): NetworkResult fun handle(result: NetworkResult) = when(result) { is Success -> println("Data: ${result.data}") is Failure -> println("Error: ${result.error}") // Все варианты учтены, 'else' не нужен }
Ключевые особенности:
Можно ли добавить sealed interface в отдельный файл или реализовать его вне первоначального файла?
Нет. Все типы, напрямую реализующие sealed interface, должны быть объявлены в том же файле, иначе компилятор выдаст ошибку.
Разрешается ли sealed интерфейсу иметь подинтерфейсы вне файла объявления?
Нет. Подинтерфейсы также должны находиться в этом же файле. Вся иерархия закрыта внутри файла.
Влияют ли sealed интерфейсы на рантайм-производительность?
Нет напрямую, но они позволяют использовать безопасные проверки типов на этапе компиляции, что уменьшает вероятность ошибок в рантайме, упрощает код и может опосредованно ускорить тестирование.
Разработчик объявляет sealed interface NetworkAction в одном файле, но реализации разбросаны по разным классам и файлам. Поздно выявляется проблема: компилятор сигнализирует о нарушении правила, исправить структуру сложно, особенно в большом проекте.
Плюсы:
Минусы:
Sealed интерфейс OrderResult и классы Success/Failure объявляются внутри одного файла. Проверка when всегда исчерпывающая, ни одна ветка не пропущена.
Плюсы:
Минусы: