Menu
Coddy logo textTech

Gerarchie sigillate

Fa parte della sezione Programmazione orientata agli oggetti del percorso Kotlin di Coddy. Lezione 34 di 57.

Una classe o un'interfaccia sealed ha un insieme chiuso di sottoclassi dirette, tutte dichiarate nello stesso pacchetto e modulo. Il compilatore le conosce tutte, il che è adatto a risultati che hanno un numero fisso di forme:

sealed interface Result
data class Success(val value: Int) : Result
data class Failure(val reason: String) : Result

fun parseAge(text: String): Result {
    val n = text.toIntOrNull() ?: return Failure("not a number: $text")
    return if (n in 0..150) Success(n) else Failure("out of range: $n")
}

All'interno di main:

println(parseAge("42"))
println(parseAge("abc"))
println(parseAge("200"))

Output:

Success(value=42)
Failure(reason=not a number: abc)
Failure(reason=out of range: 200)

Poiché il set è chiuso, un when su un tipo sealed è esaustivo senza else. Se qualcuno aggiunge una sottoclasse in seguito, ogni when di questo tipo smette di compilare finché non gestisce il nuovo caso, quindi nessun caso viene dimenticato:

sealed interface Result
data class Success(val value: Int) : Result
data class Failure(val reason: String) : Result

fun describe(r: Result) = when (r) {
    is Success -> "ok: ${r.value}"
    is Failure -> "error: ${r.reason}"
}

All'interno di main:

println(describe(Success(7)))
println(describe(Failure("timeout")))

Output:

ok: 7
error: timeout

Un caso senza dati è un data object: una singola istanza con un toString() leggibile. Il suo ramo when non ha bisogno di is, perché esiste una sola istanza. Gli altri casi possono essere classi di dati, oggetti o classi ordinarie:

sealed interface Command
data object Quit : Command
data class Move(val steps: Int) : Command
data class Say(val text: String) : Command

fun parse(line: String): Command = when {
    line == "quit" -> Quit
    line.startsWith("move ") -> Move(line.drop(5).toInt())
    else -> Say(line)
}

fun run(c: Command) = when (c) {
    Quit -> "bye"
    is Move -> "moving ${c.steps}"
    is Say -> "saying ${c.text}"
}

All'interno di main:

for (line in listOf("move 3", "hello", "quit")) {
    val c = parse(line)
    println("$c: ${run(c)}")
}

Output:

Move(steps=3): moving 3
Say(text=hello): saying hello
Quit: bye

Enum o gerarchia sealed? Un enum è un insieme fisso di singole istanze che hanno tutte le stesse proprietà. Una gerarchia sealed consente a ogni caso di contenere i propri dati, e un caso come Move può avere molte istanze con valori diversi:

enum class Light { RED, YELLOW, GREEN }          // stessa struttura, un'istanza per ciascuno

sealed interface Payment                          // ogni caso ha i propri dati
data class Card(val number: String) : Payment
data class Transfer(val iban: String, val reference: String) : Payment
data object Cash : Payment
challenge icon

Sfida

Facile

Un robot comprende i comandi dell’interfaccia sealed Command: Move(steps), Turn(left), Report e Invalid(text), che sono forniti. Completa parse(line): move 3 restituisce Move(3), turn left e turn right restituiscono Turn, report restituisce Report e qualsiasi altra cosa, incluso un movimento senza un numero valido, restituisce Invalid con la riga. Poi completa Robot.execute(command) con un when esaustivo e senza else. Il robot parte da (0, 0) rivolto verso N (il nord è y + 1, l’est è x + 1). Restituisce moved to (0, 3), facing W, at (0, 3) facing W oppure ignored.

Il codice fornito analizza ogni riga e stampa Move(steps=3) -> moved to (0, 3).

Il tuo codice va inserito in Robot.kt, Parser.kt, Command.kt, Move.kt, Turn.kt, Report.kt e Invalid.kt. Main.kt contiene il codice di input/output fornito e non può essere modificato.

Provalo tu

fun main() {
    // Codice di input/output fornito: lascialo così com'è
    val input = generateSequence(::readLine).toList()
    val robot = Robot()
    for (line in input) {
        val command = parse(line)
        println("$command -> ${robot.execute(command)}")
    }
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Playground Kotlin