Я думаю, что документация означает расширение, на самом деле не расширение перечислений, а инструмент, такой как перечисления, с большей мощностью, поскольку он может удерживать состояние. давайте посмотрим на ваш пример с перечислениями.
sealed class SealedMessageType
class MessageSuccess (val msg: String) : SealedMessageType()
class MessageFailure (val e: Exeception) : SealedMessageType()
enum class EnumMessageType {
Success,
Failure
}
и теперь, если вы используете перечисления, у вас есть:
val enumMessageType: EnumMessageType = callNetwork()
when(enumMessageType) {
EnumMessageType.Success -> { TODO() }
EnumMessageType.Failure -> { TODO() }
}
здесь, когда вы используете перечисления, вы не можете получить данные своего результата из перечислений, и вам нужно получить сообщение или ошибку с какой-либо другой переменной. единственное, что вы можете получить, это тип результата без его состояния. но с закрытыми классами:
val sealedMessageType: SealedMessageType = callNetwork()
when(sealedMessageType) {
is MessageSuccess -> { println(sealedMessageType.msg) }
is MessageFailure -> { throw sealedMessageType.e }
}
IDE может интеллектуально преобразовать ваш результат, и вы можете получить состояние своего результата (в случае успеха - сообщение, в случае неудачи - исключение). это то, что документ подразумевает под расширением.
но в целом вы правы, запечатанный класс - это наследование. Фактически, запечатанный класс - это не что иное, как абстрактный класс, который имеет частный конструктор и не может быть создан. давайте посмотрим на распакованный java-код:
@Metadata(
mv = {1, 4, 0},
bv = {1, 0, 3},
k = 1,
d1 = {"\u0000\u0014\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0000\b6\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002\u0082\u0001\u0002\u0003\u0004¨\u0006\u0005"},
d2 = {"Lcom/example/customview/SealedMessageType;", "", "()V", "Lcom/example/customview/MessageSuccess;", "Lcom/example/customview/MessageFailure;", "app"}
)
public abstract class SealedMessageType {
private SealedMessageType() {
}
// $FF: synthetic method
public SealedMessageType(DefaultConstructorMarker $constructor_marker) {
this();
}
}
@Metadata(
mv = {1, 4, 0},
bv = {1, 0, 3},
k = 1,
d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\u0018\u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u00020\u0003¢\u0006\u0002\u0010\u0004R\u0011\u0010\u0002\u001a\u00020\u0003¢\u0006\b\n\u0000\u001a\u0004\b\u0005\u0010\u0006¨\u0006\u0007"},
d2 = {"Lcom/example/customview/MessageSuccess;", "Lcom/example/customview/SealedMessageType;", "msg", "", "(Ljava/lang/String;)V", "getMsg", "()Ljava/lang/String;", "app"}
)
public final class MessageSuccess extends SealedMessageType {
@NotNull
private final String msg;
@NotNull
public final String getMsg() {
return this.msg;
}
public MessageSuccess(@NotNull String msg) {
Intrinsics.checkNotNullParameter(msg, "msg");
super((DefaultConstructorMarker)null);
this.msg = msg;
}
}
здесь вы можете видеть, что SealedMessageType
на самом деле является абстрактным классом. Единственное различие между абстрактным классом и запечатанным классом состоит в том, что компилятор генерирует некоторые метаданные для запечатанных классов и может предупреждать вас об отсутствующих ветвях, когда вы используете ключевое слово when
, чего нельзя сделать с использованием абстрактных классов. вы можете видеть в приведенном выше коде, что метаданные класса SealedMessageType
содержат как MessageSuccess
, так и MessageFailure
как дочерние классы, а метаданные MessageSuccess
также содержат SealedMessageType
как родительский. если вы используете абстрактные классы, таких метаданных нет.
если вы воспользуетесь этим простым приемом, компилятор выдаст ошибку, если вы пропустите какие-либо ветки, и IDE может помочь вам реализовать отсутствующие ветки с помощью Alt+Enter
. уловка состоит в том, чтобы определить исчерпывающую функцию расширения:
fun main() {
when(callNetwork()) { // error: when' expression must be exhaustive, add necessary 'is MessageSuccess', 'is MessageFailure' branches or 'else' branch instead
}.exhaustive()
}
fun Any?.exhaustive() = this
fun callNetwork(): SealedMessageType {
TODO()
}
person
mohsen
schedule
24.10.2020
object
- одноэлементным, - в точности эквивалентен перечислению. - person Louis Wasserman   schedule 24.10.2020object
, это класс, который может иметь только один экземпляр. - person Louis Wasserman   schedule 24.10.2020