Funktionen Grundlagen Teil 2
Schön das Sie interessiert sind an einer Weiterbildung Ihres Wissens rund um Funktionen.
In dieser Lektion werden wir unsere Kenntnisse rund um Funktionen vertiefen. Wir haben in unserer letzten Lektionen die Grundlagen über Funktionen erlernt, aber es gibt noch mehr zu entdecken. Wir werden einige spezielle Techniken lernen wie Variadics, optionale Parameter oder Tuples.
Diese Techniken werden sicherlich erst in fortgeschrittenen Tutorials verwendet werden, sie aber bereits im Grundwissen aufzuführen halten wir für richtig.
Für diesen Teil gibt es auch ein Video Tutorial hier auf YouTube.
Inhalt
Optionale Parameter
Konstante und Variable Parameter
In-Out Parameter
Tuples
Multiple Rückgabewerte mit Tuples
Variadic – Variable Parameteranzahl
Optionale Parameter
Dank optionaler Parameter können wir bestimmen was passiert wenn eine Funktion ohne einen bestimmten Wert aufgerufen wird. Bei optionalen Parametern gilt es eine Grundregel einzuhalten. Die optionalen Parameter stehen immer am Ende der Parameter die man definiert. Habe ich z.B. eine Funktion bei der zwei Parameter nicht optional sind, schreibe ich diese als erstes in meine Parameterliste gefolgt von den optionalen Parametern.
Die Definition von optionalen Parametern ist erstaunlich einfach. Nach der Typ Definition machen wir direkt einen Zuweisungsoperator gefolgt von dem Wert den die Variable annehmen soll falls diese beim Funktionsaufruf nicht gefüllt ist.
1 2 3 4 5 6 |
func verbindeStrings(string1: String, string2: String, verbindungsZeichen: String = " ") -> String { return string1 + verbindungsZeichen + string2 } var stefanString = verbindeStrings("Stefan", "Popp") var ralfString = verbindeStrings("Ralf", "Peters", verbindungsZeichen: "-") |
Wir definieren func verbindeStrings. Die Funktion soll zwei Strings miteinander verbinden. Wir haben drei Parameter: string1 und string2 jeweils vom Typ String und der dritte Parameter, der verbindungsZeichen heißt und zwischen den beiden Strings eingefügt werden soll. Wir sehen das nach der Typendefinition ein Zuweisungsoperator kommt, gefolgt von einem String der nur ein Leerzeichen enthält.
Wenn wir die Funktion jetzt aufrufen mit den Werten Stefan und Popp wird bei der Rückgabe aus der Funktion der String Stefan Popp in der Variable meinString gespeichert. Da wir den dritten Parameter weggelassen haben wird automatisch das Leerzeichen zwischen den beiden Strings eingefügt. Bei der Definition der Variable ralfString haben wir den dritten Parameter mit einem Bindestrich angegeben. Der optionale Parameter wird dadurch überschrieben und wir bekommen als Rückgabewert Ralf-Peters.
Was man an diesem Beispiel bereits erkennt ist das optionale Parameter immer benannt sind. Wir kenne benannte Parameter aus dem ersten Teil dieser Lektion. Dieses Verhalten kann man nicht beeinflussen!
Abschließend noch einige Beispiele und Anwendungen für optionale Parameter. In den Lektionen über Objektorientierung werden wir zusätzlich lernen wie wir optionale Objekte erstellen können.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
func potenziere(zahl: CFloat, hoch: CFloat = 2) -> CFloat { return powf(zahl, hoch) } func benutzerGruß(benutzerName: String = "") -> String { if benutzerName == "" { return "Hallo unbekannter Benutzer!" } return "Hallo \(benutzerName)!" } println(potenziere(4, hoch: 4)) println(potenziere(2)) println(benutzerGruß()) println(benutzerGruß(benutzerName: "geehrter Tutorial Leser")) |
Wie man schön erkennen kann, können wir einen beliebigen Wert oder den Standardwert „2“ nehmen um den ersten Parameter zu potenzieren. Bei der Funktion um den Benutzer zu Grüßen haben wir die Möglichkeit den Benutzernamen anzugeben. Sollte dieser nicht verfügbar sein wird er mit einem Standardtext gegrüßt.
Es wird häufig der Fall auftreten in dem Sie optionale Parameter nutzen möchten. Die Syntax und Verwendung ist deutlich einfacher als in Objective-C und ist für uns eine deutliche Verbesserung durch Apple.
Konstante und Variable Parameter
Funktionsparameter sind in Swift standardmäßig Konstant. Das bedeutet falls wenn wir den Wert eins Funktionsparameters ändern möchten, erzeugt der Swift Compiler einen Fehler.
1 2 3 4 |
func testFunktion(wertA: Int) { wertA = 5 // Erzeugt einen Fehler! } testFunktion(12) |
Wenn man den Wert innerhalb der Funktion ändern möchte muss man im Funktionskopf bei dem betreffenden Parameter das Schlüsselwort var schreiben. Achtung! Der Wert kann zwar innerhalb der Funktion geändert werden, er wird aber nicht ausserhalb der Funktion übernommen! Für dieses Verhalten muss man In-Out Parameter benutzen. Durch das voranstellen des Schlüsselwortes var können wir jetzt wertA ändern.
1 2 3 4 5 |
func testFunktion(var wertA: Int) { wertA = 5 println(wertA) } testFunktion(12) |
In-Out Parameter
Es kann vorkommen das man Variablen die ausserhalb einer Funktion definiert sind, innerhalb einer Funktion abändern möchte. Damit man dies tun kann muss man dem Parameternamen im Funktionskopf das Schlüsselwort inout voranstellen. Variablen die man an die Funktion übergeben muss, hat man mit einem „&“ Zeichen vorangestellt zu übergeben. Was das & Zeichen bedeutet kommt in einem späteren Kapitel in dem wir Pointer behandeln werden.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
func vertauscheVariablenInhalt(inout wertA: Int, inout wertB: Int) { var temporär: Int = wertA wertA = wertB wertB = temporär } var x = 3 var y = 5 // Ausgeben der Wert println("\(x) \(y)") // Vertauschen der Werte vertauscheVariablenInhalt(&x, &y) // Ausgeben der Werte println("\(x) \(y)") |
Die Funktion func vertauscheVariablenInhalt(inout wertA: Int, inout wertB: Int) nimmt zwei Werte mit inout entgegen. Wir möchten die Werte der beiden Variablen x und y vertauschen. In der Funktion erstellen wir eine temporäre Variable in der wir uns den Wert von wertA merken. Danach überschreiben wir die Variable wertA mit dem Inhalt aus wertB. Als letzten Schritt speichern wir den gemerkten Wert aus der Variable temporär in wertB.
Die Werte sind erfolgreich vertauscht und wir prüfen das indem wir zwei Werte definieren. Wir geben uns die initialen Werte mit println() aus und rufen die Methode vertauscheVariablenInhalte() auf. Im Anschluss geben wir uns erneut die Werte aus und stellen fest das die Inhalte erfolgreich vertauscht wurden.
inout kann in einigen Fällen viele Zeilen Programmcode ersparen. Am Anfang sollte man diese Methodik aber weitestgehend vermeiden da es auch eine tendenziell große Fehlerquelle für Anfänger ist.
Tuples
Tuples eigenen sich hervorragend um zusammengehörende Daten zusammenzufassen. Das kann eine Matrize aus der Mathematik sein oder auch die Namen eines Hochzeitspaares. Für uns bringen Tuples eine schöne Möglichkeit Daten sinnvoll anzuordnen und anzusprechen.
1 2 3 |
var authorTuple = ("Stefan Popp", "Author", "Informatiker") println(authorTuple.0) // Gibt "Stefan Popp" aus println(authorTuple.1) // Gibt "Author" aus |
Wir haben eine Variable vom Namen authorTuple. Ein Tuple wird initialisiert indem wir unsere Werte einfach kommagetrennt zwischen normale Klammern schreiben.
Der Zugriff auf die Werte erfolgt bei dieser Schreibweise durch den Variablenname, gefolgt von einem Punkt und der Position an dem der Wert im Tuple steht. Die Position beginnt aber nicht bei „1“ sonder bei „0“. In Swift beginnen Datensammlungen stets mit der Position „0“.
Ähnlich wie bei Funktionen können wir auch die Daten in Tuples benennen. Dafür schreiben wir unseren Namen einfach vor den Wert und trennen das ganze mit einem Doppelpunkt.
1 2 3 4 5 6 7 8 9 |
var authorTuple = (Name: "Stefan Popp", Status: "Author", Beruf: "Informatiker") // Zugriff über den Namen println(authorTuple.Name) println(authorTuple.Status) // Zugriff über Index ist weiterhin möglich println(authorTuple.0) println(authorTuple.1) |
Der Zugriff über den Index ist natürlich weiterhin möglich.
Tuples kann man auch verschachteln und dadurch Daten relativ einfach zusammenstellen. Aus unserer Sicht gibt es aber für komplexe Datenstrukturen deutlich geeignetere Datentypen. Ein gewaltiger Nachteil der Tuples ist zudem, dass sie nicht iterierbar sind. Es gibt keinen einfachen Weg mit Schleifen auf die Daten in Tuples zuzugreifen. Selbstverständlich gibt es auch hierfür Möglichkeiten. Wenn man aber auf einfachste Weise dieses Verhalten wünscht sollte man auf Arrays oder Dictioniaries zurückgreifen. Diese Datentypen werden wir in den nächsten Kapiteln kennenlernen.
Tuples kann man auch nutzen um Daten ein wenig kompakter anzuordnen und zu speichern. Dieses Verhalten kann man auch für Funktionen nutzen. Wir werden uns das im nächsten Abschnitt im Detail ansehen.
1 2 3 4 5 6 |
// Ein Tupple erstellen mit 2 Datensätzen var einPunkt = (xAchse: 12, yAchse: 14) // Zwei Variablen Names x und y erstellen // Werte aus "einPunkt" zuweisen let (x, y) = einPunkt |
In unserem letzten Beispiel sehen wir wie wir ein Tuple erstellen und in zwei Variablen wieder auflösen können.
Multiple Rückgabewerte mit Tuples
Statt nur einen oder keinen Rückgabewert zu definieren lässt uns Swift auch einen Tuple definieren. Die Rückgabewerte könne wir auch benennen und die Namen ausserhalb der Funktion wieder verwenden.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
func testMethode() -> (Int, Int) { return (1,5) } func zweiteTestMethode() -> (x: Int, y: Int) { return (2, 3) } var testTuple = testMethode() println("Werte sind \(testTuple.0) und \(testTuple.1)") var zweiterTestTuple = zweiteTestMethode() println("Werte sind \(zweiterTestTuple.x) und \(zweiterTestTuple.y)") |
Variadic – Variable Parameteranzahl
Manchmal kommt es vor das man sehr viele Parameter an eine Funktion übergeben möchte. Dies benötigt man z.B. für eine Funktion mit der man den Durchschnitt von vielen Werten berechnet.
Wenn wir von variablen Parametern in Swift sprechen meinen wir Variadics. Ein Funktion mit Variadic kann mit Null oder mehr Werten gefüttert werden. Ein Variadic ist immer der einzige oder der letzte Parameter in einem Funktionskopf. Mehrere Variadics vom gleichen Datentyp sind nicht möglich!
func durchschnitt(werte: Double ...) {} Im Funktionskopf schreiben wir den Namen der Variable den unser Variadic in der Funktion haben soll. Getrennt mit einem Doppelpunkt schreiben wir den Datentypen der eingegeben wird. Durch die drei Punkte sagen wir das eine nicht bestimmte Anzahl an Parametern übergeben werden kann.
Die Variable werte können wir in einer „for“-Schleife iterieren. Mit unserem folgenden Beispiel haben wir eine Funktion implementiert die uns den Durchschnitt für die Werte liefert die wir eingeben.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
func durchschnitt(werte: Double ...) -> Double { // Gebe 0 zurück wenn keine Parameter übergeben wurden if (werte.count == 0) { return 0.0; } // Variable in der wir alle Werte addieren var gesamtSumme = 0.0 // Iteriere über alle Werte for wert in werte { // Addiere aktuellen Wert auf die Gesamtsumme gesamtSumme += wert } // Summe / Anzahl teilen. // Konvertiere (werte.count) Int zu Double return (gesamtSumme / Double(werte.count)) } // Aufruf ohne Parameter sollte 0.0 zurückliefern println(durchschnitt()) // Liefert 5 zurück println(durchschnitt(2.0, 3.0, 5.0, 10.0)) // Liefert 8.5 zurück println(durchschnitt(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)) |
Wie geht es weiter?
In den kommenden Lektionen werden wir weitere Themen behandeln Konstanten. Wir hoffen das diese Lektion hilfreich für Sie war und Sie Funktionen nun einsetzen können.
Über Kritik und Feedback würden wir uns freuen.
Vielen Dank!
11 Comments
Das Tutorial ist echt klasse. Wird es eine Variante im Rahmen Einer DVD Produktion erscheinen?
Viele Grüße
Achim
Hallo Achim,
vielen Dank für deine Frage.
Aktuell ist von unserer Seite her nichts geplant. Wir arbeiten aktuell noch unser Konzept aus inwiefern wir uns für die Zukunft aufstellen möchten.
Dafür ist uns vor allem das Feedback der Community, wie auch von dir sehr wichtig.
Eine DVD in Eigenproduktion wird es aber von unserer Seite her nicht geben.
Vielen Dank
– Stefan und Ralf
Hallo Stefan & Ralf
Ich danke euch sehr dass ihr diese Tutorials macht. Das ist wirklich nicht selbstverständlich & freut mich enorm.
Vielen Dank!
Luca
Hallo Luca,
danke für dein Feedback. Wir hoffen das du auch in Zukunft noch viel Freude an unseren Tutorials haben wirst.
LG
Stefan & Ralf
Hallo Stefan & Ralf,
Erstmal Danke für die ganzen Tutorials.
Nun zu meiner Frage: Ich habe bei der powf Funktion mal ausprobiert ob die auch mit Doubles funktioniert (hat nicht funktioniert). Gibt es eine Möglichkeit, diese auch mit einem Double zu nutzen oder gibt es einen anderen Weg Doubles in Swift zu potenzieren?
Viele Grüße
johjoh
Super Tutorial!
Bin auf dem Weg Google->Amazon->Buch auf das Tutorial gestossen.
Die Tupfes sind Spitze – hätte ich in anderen Programmsprachen schon benötigt und musste mir anders behelfen.
Aber die Variadics sind echt der Hammer! Bin schon gespannt wie es im Tutorial weiter geht.
Viele Grüße
Hp.
Hallo! Super Tutorials habt Ihr da!
Aber eine kleine Frage hätte ich. Im letzten Beispiel nutzt ihr folgenden Befehl:
Double …
Könnt ihr mir bitte sagen, was die 3 Punkte genau bedeuten?
Super Tutorial! Ich bin jahrelanger Java Programmierer und finde euer Tutorial ermöglicht es mein bisheriges wissen auf Swift zu matchen.
Bringt ihr die Tutorials von Kapitel 3 auch noch in Blog-Form oder bleibt es beim YouTube Video? Wäre sehr schade, da mir persönlich die Blog-Form mehr zusagt.
So noch eine Inhaltliche Frage/Anmerkung. Ihr nutzt manchmal zur Variablendeklaration var und manchmal let. Bin ich blind oder habt ihr den Unterschied nicht erklärt? Wäre super wenn ihr das noch beim ersten verwenden erklären könntet.
Weiter so und LG
Hallo Christian,
vielen Dank für dein Lob.
Wir versuchen natürlich alle Tutorials früher oder später auch in Schriftform zu bringen. Da dies sehr zeitaufwendig ist, kann es aber leider zu Verzögerungen kommen. Wir bleiben aber dran.
Zu deiner Frage: Ja die Variablen- und Konstantendeklaration haben wir in unseren ersten Lektionen erklärt.
Variablen tauchen bei Zeichenketten-Lektion auf und Konstanten in der Gleichnamigen. Diese beiden sind auch in Schriftform vorhanden 😉
Beste Grüße
– Ralf
Was soll dieses powf sein? Dies wird mir nur als Fehler markiert.
Hallo Tho,
das ganze wurde vereinheitlicht zu pow() und wird genutzt um Potenzen zu errechnen.