Indlejring og kombination af sealed-hierarkier
Byg komplekse tilstandsmaskiner ved at indlejre sealed-typer.
Indlejring og kombination af sealed-hierarkier er en gratis Kotlin Academy-lektion på CoddyKit. Dette er lektion 4 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Kotlin Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Kotlin Academy-kurset indeholder 4 lektioner i alt.
Sammensætning af tilstandstræer
Tilstande fra den virkelige verden har ofte flere dimensioner. Indlejr sealed-typer, eller kombinér separate hierarkier, for at modellere komplekse domæner på en overskuelig måde.
Indlejret sealed-klasse
Erklær underordnede sealed-typer inde i en ydre sealed-type. Compileren håndhæver stadig udtømmelighed på tværs af hele træet.
sealed class UiState {
object Loading : UiState()
sealed class Loaded : UiState() {
data class Success(val items: List<String>) : Loaded()
data class Empty(val message: String) : Loaded()
}
data class Error(val msg: String) : UiState()
}
fun render(s: UiState) = when (s) {
UiState.Loading -> "loading"
is UiState.Loaded.Success -> "${s.items.size} items"
is UiState.Loaded.Empty -> "empty: ${s.message}"
is UiState.Error -> "err: ${s.msg}"
}
fun main() {
println(render(UiState.Loaded.Success(listOf("a", "b"))))
}Sealed-grænseflader til blandede egenskaber
Brug sealed-grænseflader, når en tilstand har flere uafhængige aspekter – hvert aspekt er en separat grænseflade.
sealed interface Authenticated
data class User(val id: Int) : Authenticated
object Guest
sealed interface Permission
object Read : Permission
object Write : Permission
fun describe(a: Authenticated, p: Permission): String = when {
a is User && p is Write -> "user ${a.id} can write"
a is User -> "user ${a.id} can read"
else -> "?"
}
fun main() {
println(describe(User(1), Write))
}Kombination af hierarkier
Send to sealed-værdier, og vælg ud fra deres kombination – brug et when-udtryk med betingelser.
sealed class Theme { object Light : Theme(); object Dark : Theme() }
sealed class Lang { object En : Lang(); object Tr : Lang() }
fun greet(theme: Theme, lang: Lang) = when {
theme is Theme.Dark && lang is Lang.Tr -> "Karanlik Merhaba"
theme is Theme.Light && lang is Lang.Tr -> "Aydinlik Merhaba"
theme is Theme.Dark -> "Dark Hello"
theme is Theme.Light -> "Light Hello"
else -> "?"
}
fun main() {
println(greet(Theme.Dark, Lang.Tr))
}Tilstandsmaskine med indlejrede varianter
Modellér arbejdsgange i flere trin som indlejrede sealed-typer – hvert trin har sine egne varianter.
sealed class Checkout {
object Start : Checkout()
sealed class Payment : Checkout() {
object Pending : Payment()
data class Failed(val reason: String) : Payment()
object Captured : Payment()
}
object Shipped : Checkout()
object Delivered : Checkout()
}
fun describe(c: Checkout) = when (c) {
Checkout.Start -> "starting"
Checkout.Payment.Pending -> "awaiting payment"
is Checkout.Payment.Failed -> "payment failed: ${c.reason}"
Checkout.Payment.Captured -> "paid"
Checkout.Shipped -> "shipped"
Checkout.Delivered -> "delivered"
}
fun main() {
println(describe(Checkout.Payment.Failed("card declined")))
}Genbrug af sealed-hierarkier på tværs af moduler
Sealed-typer defineres bedst pr. modul. Ved sammensætning på tværs af moduler skal du eksponere en sealed-grænseflade, så hvert modul kan tilføje sine egne implementeringer.
sealed interface Notification
data class Email(val to: String) : Notification
data class Sms(val phone: String) : Notification
fun send(n: Notification) = when (n) {
is Email -> "sending email to ${n.to}"
is Sms -> "texting ${n.phone}"
}
fun main() {
println(send(Email("a@example.com")))
}Fælles basisegenskaber
Sealed-klasser kan erklære fælles egenskaber – alle undertyper arver dem. Det holder tilstand og metadata DRY.
sealed class HttpResponse(val code: Int) {
class Ok(val body: String) : HttpResponse(200)
class NotFound(val path: String) : HttpResponse(404)
class ServerError(val cause: String) : HttpResponse(500)
}
fun describe(r: HttpResponse) = "[${r.code}] " + when (r) {
is HttpResponse.Ok -> r.body
is HttpResponse.NotFound -> "not found: ${r.path}"
is HttpResponse.ServerError -> "fail: ${r.cause}"
}
fun main() {
println(describe(HttpResponse.Ok("hello")))
}Modellering af rekursive træer
Sealed-typer beskriver naturligt rekursive strukturer som udtrykstræer.
sealed class Expr {
data class Num(val value: Int) : Expr()
data class Add(val left: Expr, val right: Expr) : Expr()
data class Mul(val left: Expr, val right: Expr) : Expr()
}
fun eval(e: Expr): Int = when (e) {
is Expr.Num -> e.value
is Expr.Add -> eval(e.left) + eval(e.right)
is Expr.Mul -> eval(e.left) * eval(e.right)
}
fun main() {
val expr = Expr.Add(Expr.Num(3), Expr.Mul(Expr.Num(4), Expr.Num(5)))
println(eval(expr)) // 23
}Kombination med generiske typer
Sealed-typer kan være generiske, så du kan bruge typeangivne resultatindpakninger som Result<T>.
sealed class ApiResult<out T> {
data class Success<T>(val data: T) : ApiResult<T>()
data class Failure(val message: String) : ApiResult<Nothing>()
}
fun handle(r: ApiResult<String>) = when (r) {
is ApiResult.Success -> "got ${r.data}"
is ApiResult.Failure -> "err: ${r.message}"
}
fun main() {
println(handle(ApiResult.Success("hi")))
println(handle(ApiResult.Failure("nope")))
}Antimønster: For dyb indlejring
Dyb indlejring skjuler hensigten. Hvis et sealed-træ er mere end to niveauer dybt, bør du overveje at fladgøre det eller udtrække undertræer til deres egne filer.
sealed class Top {
sealed class Mid : Top() {
sealed class Deep : Mid() {
object Leaf : Deep()
}
}
}
fun main() {
val l = Top.Mid.Deep.Leaf
println(l::class.simpleName)
}Kombination via sammensætning
Når to tilstandsdimensioner er uafhængige, bør du foretrække sammensætning (en data-klasse, der indpakker to sealed-værdier) frem for dybt indlejrede hierarkier.
sealed class Loading { object Active : Loading(); object Idle : Loading() }
sealed class Auth { data class Signed(val id: Int) : Auth(); object Anon : Auth() }
data class AppState(val loading: Loading, val auth: Auth)
fun main() {
val s = AppState(Loading.Active, Auth.Signed(1))
println(s)
}Hurtigt tjek
Hvad anbefales, når to tilstandsdimensioner er uafhængige?
Opsummering
Indlejr sealed-typer til tilstande formet som træer, og kombinér uafhængige sealed-hierarkier med sammensætning (en indpakkende data-klasse). Tilføj fælles egenskaber til en sealed-basistype, brug generiske typer til typeangivne resultater, og modellér rekursive strukturer naturligt. Hold indlejringen lav.
Lær Kotlin med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 51
- Lektioner
- 203
Ofte stillede spørgsmål
Er lektionen “Indlejring og kombination af sealed-hierarkier” gratis?
Ja — alle 3 lektioner i læringssporet Kotlin Academy, inklusive “Indlejring og kombination af sealed-hierarkier”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Kotlin Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Indlejring og kombination af sealed-hierarkier”?
Byg komplekse tilstandsmaskiner ved at indlejre sealed-typer. Du øver dig i Kotlin Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på Kotlin Academy?
Der kræves ingen tidligere erfaring. Kotlin Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 4 af 4.
Hvor lang tid tager lektionen “Indlejring og kombination af sealed-hierarkier”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne Kotlin Academy-lektion?
Ja. Alle Kotlin Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- sealed class vs sealed interface: Hvornår skal De bruge hvad?
- Udtømmende when med sealed-hierarkier
- Modellering af UI-tilstand med sealed classes
- Indlejring og kombination af sealed-hierarkier