Wenn man alle Namen und Bezeichnungen aus einer Swift-Funktionssignatur entfernt, bleibt der Typ der Funktion übrig.
func shoppingList(item: String, quantity: Int) -> String {
"You need to buy \(quantity) \(item)."
}
// shoppingList: (String, Int) -> String
func repeater(_ phrase: String, times: Int) -> String {
var result = ""
for _ in 1...times {
result += phrase
}
return result
}
// repeater: (String, Int) -> String
func printString(line: String) {
print(line)
}
// printString: (String) -> ()
Beachte, dass die Typen der ersten beiden Funktionen gleich sind, (String, Int) -> String, obwohl die beiden Signaturen unterschiedlich sind und die beiden Funktionen sehr unterschiedlich arbeiten. Beide nehmen einen String und ein Int als Eingabewert und geben einen String zurück. Und wie man am Typ der dritten Funktion sieht, gibt sie tatsächlich implizit () zurück, den einzigen Wert vom Typ Void, obwohl der Funktionsblock nichts zurückzugeben scheint.
Diese Funktionstypen können genauso verwendet werden wie jeder andere Typ in Swift. Zum Beispiel kann man sie bei der Deklaration von Variablen oder Konstanten verwenden. Und da Funktionen in Swift Werte sind, können bereits vorhandene Funktionen diesen Konstanten/Variablen zugewiesen werden:
var stringAndIntToString: (String, Int) -> String
stringAndIntToString = shoppingList
stringAndIntToString("carrots", 3)
// => "You need to buy 3 carrots."
Wie bei anderen Variablen/Konstanten muss der Wert, den du zuweist, den richtigen Typ haben:
stringAndIntToString = printShoppingList
// Error: Cannot assign value of type '(String) -> ()' to type '(String, Int) -> String'
Da Funktionstypen überall dort verwendet werden können, wo auch andere Typen verwendet werden können, können sie auch als Parametertypen verwendet, an andere Funktionen übergeben und aus diesen Funktionen heraus aufgerufen werden.
func apply3(to str: String, function f: (String, Int) -> String) -> String {
f(str,3)
}
// apply3: ([String], (String, Int) -> String) -> [String]
apply3(to: "eggs", function: shoppingList)
// => "You need to buy 3 eggs."
apply3(to: "eggs", function: repeater)
// => "eggseggseggs"
Ebenso können Funktionstypen als Rückgabetypen für Funktionen verwendet werden. Mit anderen Worten: Man kann Funktionen schreiben, die andere Funktionen erzeugen und zurückgeben. Wenn man diese Funktionen erstellt, kann die zurückgegebene Funktion die anderen Parameter verwenden, die an die Funktion übergeben werden, oder die lokalen Variablen, die innerhalb der übergeordneten Funktion erstellt werden.
func makeAdder(base: Int) -> (Int) -> Int {
func adder(_ i: Int) -> Int {
base + i
}
return adder
}
// makeAdder: (Int) -> (Int) -> Int
let add10 = makeAdder(base: 10)
// add10: (Int) -> Int
let subtract20 = makeAdder(base: -20)
// subtract10: (Int) -> Int
add10(5)
// => 15
subtract20(5)
// => -15
Hallo, Agent Double-Null0111.
Deine Mission, sofern du dich entscheidest, sie anzunehmen, ist es, zwei Tools zu schreiben, mit denen du in das Hauptquartier von UMBRA (United Minions Being Really Awful) eindringst und die Pläne für ihr neuestes wirklich furchtbares Vorhaben beschaffst. Für diesen Auftrag brauchst du zwei Tools.
Sobald du die geheimen Pläne hast, musst du sie schützen, sodass nur diejenigen, die das Passwort kennen, sie wieder abrufen können.
Dazu musst du die Funktion protectSecret(_ secret: String, withPassword password: String) -> (String) -> String implementieren.
Diese Funktion gibt eine weitere Funktion zurück, die mögliche Passwort-Strings als Eingabe entgegennimmt.
Wenn das eingegebene Passwort korrekt ist, gibt die neue Funktion das verborgene Geheimnis zurück. Ist das Passwort falsch, gibt die Funktion „Sorry. No hidden secrets here." zurück.
let secretFunction = protectSecret("Steal the world's supply of french fries!", withPassword: "5up3r53cr37")
secretFunction("Open sesame")
// Returns "Sorry. No hidden secrets here."
secretFunction("5up3r53cr37")
// Returns "Steal the world's supply of french fries!"
Wir haben erfahren, dass UMBRA alle ihre Safe-Kombinationen aus der Nummer des Raums ableitet, in dem sie sich befinden. Die Safe-Kombinationen entstehen, indem man wiederholt eine spezielle Funktion auf die Raumnummer anwendet. Die erste Zahl der Kombination ergibt sich also daraus, dass die Funktion auf die Raumnummer angewendet wird, die zweite daraus, dass die Funktion auf die erste Zahl angewendet wird, und die dritte daraus, dass die Funktion auf die zweite Zahl angewendet wird.
UMBRA ändert jedoch regelmäßig die Funktion, mit der die Kombinationen erzeugt werden. Dein Tool muss daher sowohl eine Raumnummer als auch die passende Funktion entgegennehmen, um die Kombination zu erzeugen.
Implementiere die Funktion generateCombination(forRoom room: Int, usingFunction f: (Int) -> Int) -> (Int, Int, Int), um die Kombination zu erzeugen, die du brauchst.
func makeCombo(_ x: Int) -> Int {
(x * 13) % 256
}
generateCombination(forRoom: 227, usingFunction: makeCombo)
// Returns (135, 219, 31)
Melde dich bei Exercism an, um Swift mit 35 Konzepte116 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.