Protokolle
Ein Protokoll beschreibt Anforderungen (wie ein Interface). Structs, Klassen und Enums können es erfüllen. Mit Protokoll-Erweiterungen gibst du Standardimplementierungen.
protocol Beschreibbar {
var name: String { get }
func beschreibe() -> String
}
extension Beschreibbar {
func beschreibe() -> String { "Ich bin \(name)" } // Standardimplementierung
func lautBeschreibe() -> String { beschreibe().uppercased() }
}
struct Hund: Beschreibbar { let name: String }
struct Auto: Beschreibbar {
let name: String
let ps: Int
func beschreibe() -> String { "\(name) mit \(ps) PS" }
}
let dinge: [any Beschreibbar] = [Hund(name: "Rex"), Auto(name: "Golf", ps: 110)]
for d in dinge { print(d.beschreibe(), "|", d.lautBeschreibe()) }
// Wichtige Standardprotokolle: Equatable, Comparable, Hashable, Codable, CustomStringConvertible
struct Version: Comparable, CustomStringConvertible {
let major: Int, minor: Int
static func < (a: Version, b: Version) -> Bool { (a.major, a.minor) < (b.major, b.minor) }
var description: String { "v\(major).\(minor)" }
}
let versionen = [Version(major: 1, minor: 4), Version(major: 1, minor: 0), Version(major: 2, minor: 1)]
print(versionen.sorted(), versionen.max()!, Version(major: 1, minor: 0) < Version(major: 1, minor: 1))Ich bin Rex | ICH BIN REX Golf mit 110 PS | GOLF MIT 110 PS [v1.0, v1.4, v2.1] v2.1 true
Extensions
Mit extension ergänzt du bestehende Typen, auch solche aus der Standardbibliothek:
extension Int {
var istGerade: Bool { self % 2 == 0 }
func hoch(_ n: Int) -> Int { n == 0 ? 1 : self * hoch(n - 1) }
}
extension String {
var umgekehrt: String { String(self.reversed()) }
func wiederholt(_ n: Int) -> String { String(repeating: self, count: n) }
}
print(4.istGerade, 7.istGerade, 2.hoch(10), "Swift".umgekehrt, "ab".wiederholt(3))true false 1024 tfiwS ababab
Generics
func tausche<T>(_ a: inout T, _ b: inout T) { let t = a; a = b; b = t }
func groesstes<T: Comparable>(_ liste: [T]) -> T? {
guard var m = liste.first else { return nil }
for x in liste where x > m { m = x }
return m
}
struct Stapel<Element> {
private var daten: [Element] = []
mutating func push(_ x: Element) { daten.append(x) }
mutating func pop() -> Element? { daten.popLast() }
var oberstes: Element? { daten.last }
var groesse: Int { daten.count }
}
var s = "a", t = "b"
tausche(&s, &t)
print(s, t, groesstes([3, 9, 4]) as Any, groesstes(["kiwi", "apfel"]) as Any, groesstes([Int]()) as Any)
var stapel = Stapel<Int>()
stapel.push(1); stapel.push(2); stapel.push(3)
print(stapel.pop() as Any, stapel.oberstes as Any, stapel.groesse)b a Optional(9) Optional("kiwi") nil
Optional(3) Optional(2) 2Fehlerbehandlung
Fehlerfälle sind Typen, die Error erfüllen. Fehlbare Funktionen markierst du mit throws, Aufrufe mit try:
enum RechenFehler: Error {
case durchNull
case negativ(wert: Double)
}
func teile(_ a: Int, _ b: Int) throws -> Int {
guard b != 0 else { throw RechenFehler.durchNull }
return a / b
}
func wurzel(_ x: Double) throws -> Double {
if x < 0 { throw RechenFehler.negativ(wert: x) }
return x.squareRoot()
}
do {
print(try teile(10, 2))
print(try teile(1, 0))
} catch RechenFehler.durchNull {
print("durch null!")
} catch {
print("anderer Fehler: \(error)")
}
do { _ = try wurzel(-4) } catch RechenFehler.negativ(let w) { print("negativ:", w) }
let ok = try? teile(9, 3) // try?: Optional statt Fehler
let schlecht = try? teile(9, 0)
print(ok as Any, schlecht as Any)
func lies(_ text: String) throws -> Int {
guard let n = Int(text) else { throw NSError(domain: "Eingabe", code: 1) }
return n
}
import Foundation
for t in ["42", "x"] {
do { print(try lies(t)) } catch { print("Fehler bei \(t)") }
}
func aufraeumen() {
defer { print("defer: aufgeräumt") } // läuft beim Verlassen des Blocks
print("arbeite")
}
aufraeumen()
enum Ergebnis2<T> { case ok(T), fehler(Error) }
let r: Result<Int, RechenFehler> = .success(5)
let r2: Result<Int, RechenFehler> = .failure(.durchNull)
for res in [r, r2] {
switch res {
case .success(let v): print("Erfolg", v)
case .failure(let e): print("Fehler", e)
}
}5 durch null! negativ: -4.0 Optional(3) nil 42 Fehler bei x arbeite defer: aufgeräumt Erfolg 5 Fehler durchNull
Merke
- Protokolle beschreiben Anforderungen, Protokoll-Extensions liefern Standardverhalten
extensionerweitert bestehende Typen- Generics
<T: Comparable>für wiederverwendbaren Code - Fehler:
enum ... : Error,throws,try/try?/try!,do-catch,defer,Result - Standardprotokolle:
Equatable,Comparable,Hashable,Codable
Aufgabe
Schreibe ein Protokoll Flaeche mit flaeche() -> Double und zwei Typen, die es erfüllen.