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 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
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.
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:
inout zwischen dem : und dem Typnamen in der Typannotation des Parameters schreibst.& 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.
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.
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.
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
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
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)
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)
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
Melde dich bei Exercism an, um Swift mit 35 Konzepte116 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.