Ненужная / неисправная проверка для абстрактного промежуточного подкласса закрытого класса, требуемого в исчерпывающем, когда

#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 .