Wenn du Daten modellierst, die nur eine bestimmte Menge möglicher Zustände annehmen können (etwa Wochentage, Himmelsrichtungen oder Tasten auf einem Controller), haben einfache Typen wie Int oder String große Nachteile.
Mit Ganzzahlen oder Strings muss dein Code ständig auf ungültige Werte prüfen (etwa einen Statuscode 999 oder einen Tippfehler wie "leftt"), und Menschen, die den Code lesen, können nicht leicht erkennen, wofür die Zahlen stehen.
Swift löst dieses Problem mit Aufzählungen (oft kurz Enums genannt). Ein Enum definiert einen gemeinsamen Typ für eine Gruppe verwandter, benannter Werte. Weil der Compiler alle möglichen Fälle im Voraus kennt, kann er deinen Code zur Kompilierzeit auf Korrektheit und Vollständigkeit prüfen. Enums können auch Methoden, Initialisierer und berechnete Eigenschaften haben.
Definiere ein Enum mit dem Schlüsselwort enum, gefolgt vom Typnamen, und liste seine Fälle in geschweiften Klammern auf.
Nach Swift-Konvention verwendet der Typname UpperCamelCase, während jeder Fall lowerCamelCase verwendet:
enum NESButton {
case up
case down
case left
case right
case a
case b
case select
case start
}
Du kannst auch mehrere Fälle in einer Zeile definieren, getrennt durch Kommas:
enum NESButton {
case up, down, left, right, a, b, select, start
}
Um auf einen Enum-Fall zu verweisen, schreibst du den Typnamen des Enums, einen Punkt (.) und den Namen des Falls. Sobald der Typ bekannt ist oder vom Compiler abgeleitet werden kann, kannst du den Typnamen weglassen und die kürzere Punkt-Syntax verwenden:
var lastPressed = NESButton.up
// Swift infers the type, so you can omit the type name:
lastPressed = .down
let konamiCode: [NESButton] = [.up, .up, .down, .down, .left, .right, .left, .right, .b, .a]
Enums können Methoden und eigene Initialisierer definieren, genau wie Klassen und Strukturen. Innerhalb einer Enum-Methode verweist self auf den aktuellen Fallwert:
enum Coin {
case heads
case tails
init(_ value: Int) {
if value.isMultiple(of: 2) {
self = .heads
} else {
self = .tails
}
}
func flip() -> Coin {
switch self {
case .heads: return .tails
case .tails: return .heads
}
}
}
let tails = Coin(13) // .tails
let heads = Coin(0) // .heads
let flipped = heads.flip() // .tails
Enum-Fälle können mit Standardwerten vorbelegt werden, den sogenannten Rohwerten.
Alle Rohwerte in einem Enum müssen denselben Typ haben (etwa Int, String oder Character):
enum NESButton: Character {
case up = "⬆️"
case down = "⬇️"
case left = "⬅️"
case right = "➡️"
case a = "🅰️"
case b = "🅱️"
case select = "✅"
case start = "🚦"
}
print(NESButton.left.rawValue) // Prints "⬅️"
Du kannst ein Enum mit init(rawValue:) aus einem Rohwert initialisieren. Weil ein ungültiger Rohwert übergeben werden könnte, gibt dieser Initialisierer ein Optional zurück:
let upButton = NESButton(rawValue: "⬆️") // Optional(NESButton.up)
let invalid = NESButton(rawValue: "🙄") // nil
Swift kann für String- und Int-Enums automatisch Rohwerte vergeben:
String-Enums entspricht der Rohwert jedes Falls standardmäßig seinem Fallnamen.Int-Enums beginnen die Rohwerte bei 0 und erhöhen sich um 1, sofern nichts anderes angegeben ist.enum Planet: Int {
case mercury = 1, venus, earth, mars
}
print(Planet.earth.rawValue) // Prints 3
In dieser Übung verarbeitest du Logzeilen.
Jede Logzeile ist ein String, der wie folgt formatiert ist: "[<LVL>]: <MESSAGE>".
Das sind die verschiedenen Log-Level:
TRC (trace)DBG (debug)INF (info)WRN (warning)ERR (error)FTL (fatal)Du hast drei Aufgaben, die du alle erledigen musst, um die nötige Funktionalität bereitzustellen.
Definiere ein LogLevel-Enum mit sechs Fällen, die den obigen Log-Leveln entsprechen, plus einem unbekannten Fall für Log-Level, die fehlen oder nicht dem Standard entsprechen.
tracedebuginfowarningerrorfatalunknownImplementiere als Nächstes den Initialisierer von LogLevel, um den Log-Level einer Logzeile zu parsen:
LogLevel("[INF]: File deleted")
// Returns LogLevel.info
LogLevel("Something went wrong!")
// Returns LogLevel.unknown
Der Log-Level einer Logzeile nimmt ziemlich viel Platz ein.
Um den Speicherplatz zu reduzieren, den die Logzeilen belegen, wurde ein Kurzformat entwickelt: "<ENCODED_LEVEL>:<MESSAGE>".
Der kodierte Log-Level ist eine einfache Zuordnung eines Log-Levels zu einer Zahl:
trace - 0
debug - 1
info - 4
warning - 5
error - 6
fatal - 7
unknown - 42
Implementiere die Methode shortFormat(message: String) -> String, die das verkürzte Logzeilenformat als String ausgeben kann:
let overflow = LogLevel.error
overflow.shortFormat(message: "Stack overflow")
// Returns "6:Stack overflow"
Melde dich bei Exercism an, um Swift mit 35 Konzepte116 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.