Menu
Coddy logo textTech

Protokollerweiterungen

Teil des Abschnitts Objektorientierte Programmierung der Swift-Journey von Coddy. Lektion 29 von 57.

Eine Protokollerweiterung gibt den Methoden eines Protokolls eine Standardimplementierung. Jeder konforme Typ erhält sie kostenlos, und ein Typ kann weiterhin seine eigene Version bereitstellen:

protocol Greeter {
    var name: String { get }
    func greet() -> String
}

extension Greeter {
    func greet() -> String { "Hello, \(name)!" }
}

struct English: Greeter { let name: String }
struct Pirate: Greeter {
    let name: String
    func greet() -> String { "Ahoy, \(name)!" }
}

print(English(name: "Ada").greet())
print(Pirate(name: "Ada").greet())

Ausgabe:

Hello, Ada!
Ahoy, Ada!

Eine Erweiterung kann auch neue Methoden hinzufügen, die ausschließlich aus den Anforderungen erstellt werden. Ein konformer Typ schreibt den kleinen erforderlichen Teil und erhält den Rest:

protocol Scored {
    var points: [Int] { get }
}

extension Scored {
    var total: Int { points.reduce(0, +) }
    var best: Int { points.max() ?? 0 }
    func summary() -> String { "total \(total), best \(best)" }
}

struct Player: Scored {
    let points: [Int]
}

print(Player(points: [3, 9, 4]).summary())

Ausgabe:

total 16, best 9

Dies teilt Verhalten zwischen Strukturen, Klassen und Enumerationen ohne Vererbung. Die Standardbibliothek funktioniert auf die gleiche Weise: Jede Collection erhält isEmpty, first und map durch Protokollerweiterungen.

extension Collection {
    // isEmpty, first, map, filter, ... sind alle einmal hier definiert
    // und jedes array, set, dictionary und string bekommt sie
}

Eine eingeschränkte Erweiterung fügt Methoden nur für einige konforme Typen hinzu, geschrieben mit where:

protocol Container {
    associatedtype Item
    var items: [Item] { get }
}

extension Container where Item == Int {
    var sum: Int { items.reduce(0, +) }
}

struct Box: Container {
    var items: [Int]
}

print(Box(items: [2, 5]).sum)

Ausgabe:

7
challenge icon

Aufgabe

Einfach

Deklariere ein Protokoll Priced, das var price: Int { get } (in Cent) und var formatted: String { get } erfordert. Gib formatted in einer Protokollerweiterung einen Standardwert, der $4.50 zurückgibt, und füge eine Methode isAffordable(budget:) hinzu, die zurückgibt, ob der Preis in das Budget passt. Lass die Strukturen Coffee (Preis 450) und Sandwich (mit einem gespeicherten price) diesem Protokoll entsprechen. Coffee muss den Standardwert von formatted durch coffee $4.50 ersetzen.

Der bereitgestellte Code liest ein Budget und anschließend Zeilen mit coffee oder sandwich,650. Für jedes Element gibt er formatted sowie yes oder no aus.

Dein Code gehört in Priced.swift, Coffee.swift und Sandwich.swift. main.swift enthält den bereitgestellten Eingabe-/Ausgabecode und darf nicht bearbeitet werden.

Probier es selbst

// Gelieferter Ein-/Ausgabecode: belasse ihn wie er ist
var input: [String] = []
while let line = readLine() { input.append(line) }
let budget = Int(input[0])!
for line in input.dropFirst() {
    let item: any Priced = line == "coffee" ? Coffee() : Sandwich(price: Int(line.split(separator: ",")[1])!)
    print("\(item.formatted) \(item.isAffordable(budget: budget) ? "yes" : "no")")
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Swift-Playground