Tracks
/
Swift
Swift
/
Übungen
/
Lasagne-Meister
Lasagne-Meister

Lasagne-Meister

Lernübung

Einführung

Standardwerte für Parameter

Standardwerte für Parameter kannst du für jeden beliebigen Parameter einer Funktion angeben, indem du in der Parameterliste nach der Typannotation des Parameters einen Wert zuweist. Wenn ein Standardwert für einen Parameter angegeben ist, kann der Aufrufer der Funktion diesen Parameter beim Aufruf weglassen; stattdessen wird dann der Standardwert verwendet.

func greeting(name: String = "guest", duration: Int = 2) -> String {
  "Welcome, \(name). Enjoy your \(duration) night stay."
}

greeting(name: "Bobo", duration: 7)
// Returns "Welcome, Bobo. Enjoy your 7 night stay."
greeting(duration: 3)
// Returns "Welcome, guest. Enjoy your 3 night stay."
greeting(name: "Wynona")
// Returns "Welcome, Wynona. Enjoy your 2 night stay."
greeting()
// Returns "Welcome, guest. Enjoy your 2 night stay."

Variadische Parameter

Variadische Parameter ermöglichen es einer Funktion, für einen einzelnen Parameter null oder mehr Werte eines bestimmten Typs anzunehmen. Du definierst einen variadischen Parameter, indem du drei Punkte (...) an die Typannotation des Parameters anhängst.

Innerhalb des Funktionskörpers stellt Swift diese Werte als Array des angegebenen Typs bereit:

import Foundation

func geometricMean(_ numbers: Double...) -> Double {
    var total = 1.0
    for number in numbers {
        total *= number
    }
    return pow(total, 1.0 / Double(numbers.count))
}

let result = geometricMean(1, 2, 3, 4, 5)
// result is 2.605171084697352
Note

Wenn eine Funktion nach einem variadischen Parameter noch weitere Parameter enthält, muss der erste Parameter nach dem variadischen Parameter eine explizite Argumentbezeichnung haben, damit Swift weiß, wo die Liste der variadischen Argumente endet.

In-out-Parameter

Innerhalb des Funktionskörpers werden Parameter als Konstanten behandelt, nicht als Variablen. Wenn du versuchst, den Wert eines Parameters zu ändern, gibt es einen Fehler zur Kompilierzeit. Wenn eine Funktion den Wert eines Parameters ändern möchte, muss sie einen In-out-Parameter verwenden, um diese Veränderbarkeit explizit zu machen.

Um In-out-Parameter zu verwenden, muss man auf drei Dinge achten:

  1. In der Funktionsdefinition musst du In-out-Parameter explizit kennzeichnen, indem du das Schlüsselwort inout zwischen dem : und dem Typnamen in der Typannotation des Parameters schreibst.
  2. Der Wert, der an den In-out-Parameter übergeben wird, muss als Variable deklariert sein, nicht als Konstante. Ebenso kann er kein Literal sein.
  3. Dem Variablennamen muss beim Aufruf der Funktion ein & vorangestellt werden, wodurch er explizit als veränderbar gekennzeichnet wird.

Wenn du das tust, erstellt die Funktion eine interne Kopie des In-out-Parameters und ändert sie so, wie es im Funktionskörper vorgegeben ist. Wenn die Funktion zurückkehrt, kopiert sie den geänderten Wert zurück in die Variable, die übergeben wurde.

func updateVersion(_ record: inout (version: Int, title: String)) {
  record.version += 1
}

var dbRecord = (version: 2, title: "Exercism")
updateVersion(&dbRecord)

// dbRecord is now (3, "Exercism")
Bei In-out-Parametern gibt es ein paar zusätzliche Regeln, die du kennen solltest.

1  Innerhalb einer Funktion mit In-out-Parametern darfst du nicht auf die Variable verweisen, die als In-out-Parameter übergeben wurde.
2. Dieselbe Variable kann in derselben Funktion nicht als mehrere In-out-Parameter übergeben werden.
   Zum Beispiel löst `inoutFunc(&mutVar, &mutVar)` einen Compilerfehler aus.

Verschachtelte Funktionen

In Swift kannst du Funktionen innerhalb anderer Funktionen definieren. Man nennt sie verschachtelte Funktionen.

Verschachtelte Funktionen werden häufig als private Hilfsfunktionen genutzt, die bestimmte Aufgaben für die umgebende Funktion übernehmen, ohne den äußeren Gültigkeitsbereich zu verschmutzen:

func makeNumber(_ number: Int) -> Int {
    func double(_ x: Int) -> Int {
        x * 2
    }

    func increment(_ x: Int) -> Int {
        x + 1
    }

    return number.isMultiple(of: 2) ? increment(double(number)) : double(number)
}

print(makeNumber(3)) // Prints 6
print(makeNumber(4)) // Prints 9

Verschachtelte Funktionen verhalten sich wie normale Funktionen, aber ihre Sichtbarkeit ist auf den Funktionskörper der umgebenden Funktion beschränkt.

Anleitung

In dieser Übung schreibst du noch etwas mehr Code, um dir beim Kochen deiner brillanten Lasagne aus deinem Lieblingskochbuch zu helfen.

Es gibt fünf Aufgaben, die sich alle mit der Zeit befassen, die du für das Kochen der Lasagne brauchst.

1. Das Ändern der erwarteten Ofenzeit ermöglichen

Du möchtest eine verbesserte Funktion remainingMinutesInOven schreiben, die die Anzahl der verstrichenen Minuten, die die Lasagne im Ofen war, als Parameter entgegennimmt und zurückgibt, wie viele Minuten die Lasagne noch im Ofen bleiben muss, basierend auf der erwarteten Ofenzeit in Minuten aus der vorherigen Aufgabe. Bisher hast du dich auf einen konstanten Wert expectedMinutesInOven verlassen, der von außerhalb der Funktion remainingMinutesInOven kam. Das war dir sowohl etwas zu unübersichtlich als auch nicht flexibel genug, denn es erlaubt dir nicht, die erwartete Zeit im Ofen zu ändern.

Um das aufzuräumen, definiere die Funktion remainingMinutesInOven, die die Anzahl der verstrichenen Minuten, die die Lasagne im Ofen war, als Parameter entgegennimmt, sowie einen Parameter expectedMinutesInOven mit dem Standardwert 40. Deine Funktion sollte zurückgeben, wie viele Minuten die Lasagne noch im Ofen bleiben muss, basierend auf der erwarteten Ofenzeit in Minuten aus der vorherigen Aufgabe.

remainingMinutesInOven(elapsedMinutes: 30)
// Returns 10
remainingMinutesInOven(elapsedMinutes: 30, expectedMinutesInOven: 75)
// Returns 45

2. Unterschiedliche Anzahlen von Schichten ermöglichen

Zuvor hattest du eine Funktion preparationTimeInMinutes geschrieben, die die Anzahl der Schichten, die du der Lasagne hinzugefügt hast, als Parameter entgegennimmt und zurückgibt, wie viele Minuten du für die Vorbereitung der Lasagne gebraucht hast, wobei du davon ausgehst, dass jede Schicht 2 Minuten Vorbereitung dauert. Mit dieser Funktion bist du allerdings nicht besonders zufrieden, denn du musst die Anzahl der Schichten in deiner Lasagne selbst zählen, bevor du diese Funktion aufrufen kannst, und wer hat schon Zeit dafür?

Um es dir einfacher zu machen, schreibe eine Funktion preparationTimeInMinutes, die einen variadischen Parameter layers vom Typ String entgegennimmt, in dem du die verschiedenen Schichten deiner Lasagne auflistest. Die Funktion zählt dann die Anzahl der Schichten in deiner Lasagne und gibt die benötigte Vorbereitungszeit zurück.

preparationTimeInMinutes(layers: "sauce", "noodles")
// Returns 4
preparationTimeInMinutes(layers: "sauce", "noodles", "sauce", "meat", "mozzarella", "noodles", "sauce", "eggplant", "béchamel", "noodles", "sauce", "mozzarella")
// Returns 24

3. Mengen an Nudeln und Soße berechnen

Bevor du anfängst, deine Lasagne zusammenzubauen, möchtest du sicherstellen, dass du genug Soße und Nudeln hast, um die Lasagne deiner Träume zu bauen. Für jede Nudelschicht in deiner Lasagne brauchst du 3 Nudeln. Für jede Soßenschicht in deiner Lasagne brauchst du 0,2 Liter Soße.

Definiere die Funktion quantities, die einen variadischen Parameter layers vom Typ String entgegennimmt, in dem du die verschiedenen Schichten deiner Lasagne auflistest. Die Funktion bestimmt dann die Menge an Nudeln und Soße, die für dein Gericht benötigt wird. Das Ergebnis sollte in einem Tupel vom Typ (noodles: Int, sauce: Double) zurückgegeben werden.

quantities(layers: "sauce", "noodles", "sauce", "meat", "mozzarella", "noodles", "sauce", "eggplant", "béchamel", "noodles", "sauce", "mozzarella")
// Returns (noodles: 9, sauce: 0.8)
quantities(layers: "sauce", "noodles", "sauce", "noodles", "meat", "noodles", "mozzarella")
// Returns (noodles: 9, sauce: 0.4)

4. Liter direkt in Flüssigunzen umrechnen

Leider ist das Volumen der Soße, die du zur Hand hast, in Flüssigunzen statt in Litern angegeben. Um dir zu helfen, festzustellen, ob du genug Soße zur Hand hast, schreibe eine Funktion toOz, die einen In-Out-Tupel-Parameter (noodles: Int, sauce: Double) entgegennimmt und die Soßenmenge in Flüssigunzen umrechnet. Beachte, dass ein Liter 33,814 Flüssigunzen entspricht.

var amount = (noodles: 9, sauce: 0.8)
toOz(&amount)

amount
// Returns (noodles: 9, sauce: 27.0512)

5. Den besten Wein zum Servieren bestimmen

Zum Schluss möchtest du wissen, welche Art von Wein du zu deiner Lasagne servieren solltest. Du hast gehört, dass du Weißwein servieren solltest, wenn mehr Mozzarella, Ricotta und Béchamel in der Lasagne sind als Fleisch und Soße, und ansonsten Rotwein. Schreibe eine Funktion redWine, die einen variadischen Parameter layers vom Typ String entgegennimmt, in dem du die verschiedenen Schichten deiner Lasagne auflistest. Die Funktion verwendet fünf verschachtelte Funktionen, um die Anzahl der Schichten von Mozzarella, Ricotta, Béchamel, Soße und Fleisch in der Lasagne zu bestimmen, und vergleicht die Anzahlen der Schichten, um zu entscheiden, ob Rotwein serviert werden sollte. Dabei gibt sie true zurück, wenn ja, und false, wenn nicht.

redWine(layers: "sauce", "noodles", "sauce", "meat", "mozzarella", "noodles", "sauce", "eggplant", "béchamel", "noodles", "sauce", "mozzarella")
// Returns true
redWine(layers: "sauce", "noodles", "béchamel", "meat", "mozzarella", "noodles", "ricotta", "eggplant", "béchamel", "noodles", "sauce", "mozzarella")
// Returns false
Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab
Swift Exercism

Bereit, mit Lasagne-Meister zu starten?

Melde dich bei Exercism an, um Swift mit 35 Konzepte116 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.