#kotlin #pattern-matching #sealed-class
#kotlin #сопоставление с образцом #sealed-class
Вопрос:
У меня есть закрытая иерархия классов следующим образом:
sealed class Base
class A : Base()
abstract class B : Base()
class C : Base()
class D : Base()
Тогда я хочу иметь исчерпывающий when
:
fun main() {
val c: Base = C()
when (c) {
is A -> println("A")
is C -> println("C")
is D -> println("D")
}.let {}
}
Но это не разрешено, потому что
'when' expression must be exhaustive, add necessary 'is B' branch or 'else' branch instead
Но это неправда! Я рассмотрел все возможности. Нет значения, которое не соответствует моему when .
Кроме того, если я добавлю is C
предложение:
when (c) {
is A -> println("A")
is B -> println("B")
is C -> println("C")
is D -> println("D")
}.let {}
На самом деле он не вызывается. C
печатается.
На самом деле это проблема и в другом направлении. Скажем, я хочу, чтобы одна и та же логика обрабатывала все подклассы B
: C
и D
:
when (c) {
is A -> println("A")
is B -> println("some subclass of B")
}.let {}
Это также не допускается, даже если оно является исчерпывающим. Что здесь происходит? Это ошибка в Kotlin? Я что-то упускаю?
Комментарии:
1. Почему
B
недопустимый тип? Любая реализация поB
-прежнему является типомBase
Ответ №1:
Предполагая, что вы имели в виду, что C и D являются подклассами B, а не Base, тогда такое поведение ожидается. Способность компилятора распознавать исчерпывающий оператор when распространяется только на прямых дочерних элементов закрытого класса. C и D не являются частью контракта с закрытым классом. Это работает с вашей существующей настройкой класса, если C и D расширяют B:
when (c) {
is A -> println("A")
is B -> println("B")
}.let {}
И если вы сделаете B закрытым классом, точно так же, как A, ваш исходный код работает, и компилятор может распознать, что он исчерпывающий, не включая B в оператор when .