Im vorigen Artikel haben wir die Grundlagen der Funktionen in Swift untersucht. Funktionen haben jedoch noch viel mehr zu bieten. In diesem Artikel setzen wir unsere Erkundung der Funktionen fort und untersuchen Funktionsparameter, Verschachtelung und Typen.
Lassen Sie uns eines der Beispiele aus dem vorherigen Artikel noch einmal besuchen. Das printMessage (Nachricht :)
Funktion definiert einen Parameter, Botschaft
.
func printMessage (Nachricht: Zeichenfolge) print (Nachricht)
Wir vergeben einen Namen, Botschaft
, zu dem Parameter und verwenden Sie diesen Namen, wenn Sie die Funktion aufrufen.
printMessage (Nachricht: "Hallo, Welt!")
Beachten Sie jedoch, dass wir denselben Namen verwenden, um auf den Wert des Parameters im Rumpf der Funktion zu verweisen.
func printMessage (Nachricht: Zeichenfolge) print (Nachricht)
In Swift hat ein Parameter immer eine lokal Parametername und hat optional eine extern Parametername. Im Beispiel sind die lokalen und externen Parameternamen identisch.
Seit Swift 3 hat das Swift-Team klare API-Richtlinien definiert. Ich werde nicht auf diese Richtlinien in diesem Tutorial eingehen, aber ich möchte darauf hinweisen, dass die Definition der printMessage (Nachricht :)
Funktion weicht von diesen Richtlinien ab. Der Name der Funktion enthält das Wort Botschaft
, und der Parameter wird auch benannt Botschaft
. Mit anderen Worten, wir wiederholen uns.
Es wäre eleganter, wenn wir uns anrufen könnten printMessage (Nachricht :)
Funktion ohne Botschaft
Stichwort. Daran habe ich gedacht.
printMessage ("Hallo, Welt!")
Dies ist möglich und entspricht mehr den Swift-API-Richtlinien. Was ist aber anders? Der Unterschied ist leicht zu erkennen, wenn wir die aktualisierte Funktionsdefinition betrachten. Das aktualisierte Beispiel zeigt auch mehr über die Anatomie der Funktionen in Swift.
func printMessage (_ message: String) print (message)
In einer Funktionsdefinition wird jeder Parameter durch einen externen Parameternamen, einen lokalen Parameternamen, einen Doppelpunkt und den Typ des Parameters definiert. Wenn die lokalen und externen Parameternamen identisch sind, schreiben wir den Parameternamen nur einmal. Deshalb definiert das erste Beispiel einen Parameternamen, Botschaft
.
Wenn wir einem Parameter keinen externen Parameternamen zuordnen wollen, verwenden wir den _
, ein Unterstrich. Dadurch wird der Compiler informiert, dass der Parameter keinen externen Parameternamen hat. Dies bedeutet, dass wir den Parameternamen beim Aufruf der Funktion weglassen können.
Objective-C ist bekannt für seine langen Methodennamen. Dies mag für Außenstehende unbeholfen und unelegant erscheinen, aber es macht Methoden verständlich und, wenn sie gut gewählt werden, sehr anschaulich. Das Swift-Team verstand diesen Vorteil und führte vom ersten Tag an externe Parameternamen ein.
Wenn eine Funktion mehrere Parameter akzeptiert, ist nicht immer ersichtlich, welches Argument welchem Parameter entspricht. Sehen Sie sich das folgende Beispiel an, um das Problem besser zu verstehen. Beachten Sie, dass die Parameter keinen externen Parameternamen haben.
Funktionsstärke (_ a: Int, _ b: Int) -> Int var Ergebnis = a für _ in 1…Das
Leistung(_:_:)
Funktion erhöht den Wert vonein
vom Exponentenb
. Beide Parameter sind vom TypInt
. Während die meisten Benutzer intuitiv den Basiswert als erstes Argument und den Exponenten als zweites Argument übergeben, ist der Typ, der Name oder die Signatur der Funktion nicht klar. Wie wir im vorherigen Artikel gesehen haben, ist das Aufrufen der Funktion unkompliziert.Leistung (2, 3)Um Verwirrung zu vermeiden, können wir den Parametern einer Funktion externe Namen geben. Wir können diese externen Namen dann verwenden, wenn die Funktion aufgerufen wird, um eindeutig anzugeben, welches Argument welchem Parameter entspricht. Schauen Sie sich das aktualisierte Beispiel unten an.
Funkleistung (Basis a: Int, Exponent b: Int) -> Int var Ergebnis = a für _ in 1…Beachten Sie, dass sich der Rumpf der Funktion nicht geändert hat, da sich die lokalen Namen nicht geändert haben. Wenn wir jedoch die aktualisierte Funktion aufrufen, ist der Unterschied klar und das Ergebnis ist weniger verwirrend.
Leistung (Basis: 2, Exponent: 3)Während die Typen beider Funktionen identisch sind,
(Int, Int) -> Int
, Die Funktionen sind unterschiedlich. Mit anderen Worten, die zweite Funktion ist keine Redeklaration der ersten Funktion. Die Syntax zum Aufrufen der zweiten Funktion erinnert Sie möglicherweise an Objective-C. Die Argumente werden nicht nur klar beschrieben, sondern die Kombination von Funktions- und Parameternamen beschreibt auch den Zweck der Funktion.In einigen Fällen möchten Sie denselben Namen für den lokalen und den externen Parameternamen verwenden. Dies ist möglich und Sie müssen den Parameternamen nicht zweimal eingeben. Im folgenden Beispiel verwenden wir
Base
undExponent
als lokale und externe Parameternamen.Funktionsstärke (Basis: Int, Exponent: Int) -> Int var Ergebnis = Basis für _ in 1…Durch die Definition eines Namens für jeden Parameter dient der Parametername als lokaler und externer Name des Parameters. Dies bedeutet auch, dass wir den Körper der Funktion aktualisieren müssen.
Beachten Sie, dass Sie durch Angabe eines externen Namens für einen Parameter diesen Namen beim Aufrufen der Funktion verwenden müssen. Dies bringt uns zu Standardwerten.
Standardwerte
Im vorherigen Artikel haben wir die Standardparameterwerte behandelt. Dies ist die Funktion, die wir in diesem Artikel definiert haben.
func printDate (Datum: Datum, Format: String = "JJ / MM / TT") -> String let dateFormatter = DateFormatter () dateFormatter.dateFormat = Format Rückgabe dateFormatter.string (von: Datum)Was passiert, wenn wir keinen externen Parameternamen für den zweiten Parameter definieren, der einen Standardwert hat?
func printDate (date: Date, _ format: String = "YY / MM / dd") -> String let dateFormatter = DateFormatter () dateFormatter.dateFormat = Format Rückgabe dateFormatter.string (von: Datum)Der Compiler scheint das nicht zu interessieren. Aber wollen wir das? Es ist am besten, einen externen Parameternamen für optionale Parameter (Parameter mit einem Standardwert) zu definieren, um Verwirrung und Mehrdeutigkeit zu vermeiden.
Beachten Sie, dass wir uns im vorherigen Beispiel noch einmal wiederholen. Es ist nicht erforderlich, einen externen Parameternamen für die zu definieren
Datum
Parameter. Das nächste Beispiel zeigt wasprintDate (_: format :)
Diese Funktion würde aussehen, wenn wir den Swift-API-Richtlinien folgen würden.func printDate (_ date: Date, Format: String = "JJ / MM / TT") -> String let dateFormatter = DateFormatter () dateFormatter.dateFormat = Format Rückgabe dateFormatter.string (von: Datum)Wir können jetzt das aufrufen
formatDate (_: format :)
Funktion ohne Verwendung derDatum
Label für den ersten Parameter und mit einem optionalen Datumsformat.printDate (Date ()) PrintDate (Date (), Format: "TT / MM / JJ")2. Parameter und Mutabilität
Lassen Sie uns noch einmal das erste Beispiel dieses Tutorials, das
printMessage (_ :)
Funktion. Was passiert, wenn wir den Wert von ändern?Botschaft
Parameter innerhalb des Funktionskörpers?func printMessage (_ message: String) message = "Drucken: \ (Nachricht)" print (Nachricht)Es dauert nicht lange, bis sich der Compiler beschwert.
Die Parameter einer Funktion sind Konstanten. Mit anderen Worten, während wir auf die Werte von Funktionsparametern zugreifen können, können wir deren Wert nicht ändern. Um diese Einschränkung zu umgehen, deklarieren wir eine Variable im Rumpf der Funktion und verwenden stattdessen diese Variable.
func printMessage (_ message: String) var message = message message = "Drucken: \ (Nachricht)" print (Nachricht)3. Variadische Parameter
Während der Begriff auf den ersten Blick ungerade klingt, sind bei der Programmierung verschiedene Parameter üblich. Ein variadischer Parameter ist ein Parameter, der null oder mehr Werte akzeptiert. Die Werte müssen vom selben Typ sein. Die Verwendung von variadischen Parametern in Swift ist trivial, wie das folgende Beispiel zeigt.
func sum (_ args: Int…) -> Int var result = 0 für a in args result + = a return result sum (1, 2, 3, 4)Die Syntax ist leicht verständlich. Um einen Parameter als variadisch zu kennzeichnen, hängen Sie dem Typ des Parameters drei Punkte an. Im Funktionshauptteil ist der Parameter variadic als Array verfügbar. Im obigen Beispiel,
args
ist ein Array vonInt
Werte.Da Swift wissen muss, welche Argumente welchen Parametern entsprechen, muss ein variadischer Parameter der letzte Parameter sein. Dies impliziert auch, dass eine Funktion höchstens einen variablen Parameter haben kann.
Das Obige gilt auch, wenn eine Funktion Parameter mit Standardwerten hat. Der variadische Parameter sollte immer der letzte Parameter sein.
4. In-Out-Parameter
In diesem Tutorial haben Sie bereits erfahren, dass die Parameter einer Funktion Konstanten sind. Wenn Sie einen Wert an eine Funktion übergeben möchten, ändern Sie ihn in der Funktion und geben Sie ihn wieder aus der Funktion heraus. In-Out-Parameter sind das, was Sie brauchen.
Das folgende Beispiel zeigt ein Beispiel, wie In-Out-Parameter in Swift funktionieren und wie die Syntax aussieht.
func prefixString (_ string: inout String, mit Präfix: String) string = Präfix + StringWir definieren den ersten Parameter als In-Out-Parameter durch Hinzufügen von
inout
Stichwort. Der zweite Parameter ist ein regulärer Parameter mit einem externen Namen vonwithString
und ein lokaler Name vonPräfix
. Wie rufen wir diese Funktion auf??var input = "Welt!" prefixString (& Eingabe, mit: "Hallo",)Wir deklarieren eine Variable,
Eingang
, vom TypString
und gib es demprefixString (_: with :)
Funktion. Der zweite Parameter ist ein String-Literal. Durch Aufrufen der Funktion wird der Wert vonEingang
Variable wirdHallo Welt!
. Beachten Sie, dass dem ersten Argument ein kaufmännisches Und vorangestellt ist,&
, um anzuzeigen, dass es sich um einen In-Out-Parameter handelt.Es ist selbstverständlich, dass Konstanten und Literale nicht als In-Out-Parameter übergeben werden können. Der Compiler gibt einen Fehler aus, wenn Sie wie in den folgenden Beispielen beschrieben vorgehen.
Es ist offensichtlich, dass In-Out-Parameter keine Standardwerte haben oder variadisch sein können. Wenn Sie diese Details vergessen, erinnert der Compiler Sie mit einem Fehler.
5. Verschachtelung
In C und Objective-C können Funktionen und Methoden nicht verschachtelt werden. In Swift sind verschachtelte Funktionen jedoch recht häufig. Die Funktionen, die wir in diesem und im vorherigen Artikel gesehen haben, sind Beispiele für globale Funktionen - sie sind im globalen Bereich definiert.
Wenn wir eine Funktion innerhalb einer globalen Funktion definieren, bezeichnen wir diese Funktion als verschachtelte Funktion. Eine verschachtelte Funktion hat Zugriff auf die Werte, die in der umgebenden Funktion definiert sind. Sehen Sie sich das folgende Beispiel an, um dies besser zu verstehen.
func printMessage (_ message: String) let a = "Hallo Welt" func printHelloWorld () print (a)Während die Funktionen in diesem Beispiel nicht besonders nützlich sind, veranschaulichen sie die Idee von verschachtelten Funktionen und der Erfassung von Werten. Das
printHelloWorld ()
Funktion ist nur von innerhalb derprintMessage (_ :)
Funktion.Wie im Beispiel dargestellt, wird der
printHelloWorld ()
Funktion hat Zugriff auf die Konstanteein
. Der Wert wird von der verschachtelten Funktion erfasst und kann daher von dieser Funktion aus aufgerufen werden. Swift kümmert sich um die Erfassung von Werten, einschließlich der Verwaltung der Speicherung dieser Werte.6. Funktionsarten
Funktionen als Parameter
Im vorigen Artikel haben wir kurz auf Funktionstypen eingegangen. Eine Funktion hat einen bestimmten Typ, der sich aus den Parametertypen der Funktion und ihrem Rückgabetyp zusammensetzt. Das
printMessage (_ :)
Funktion ist beispielsweise vom Typ(String) -> ()
. Erinnere dich daran()
symbolisiertLeere
, das entspricht einem leeren Tupel.Da jede Funktion einen Typ hat, ist es möglich, eine Funktion zu definieren, die eine andere Funktion als Parameter akzeptiert. Das folgende Beispiel zeigt, wie das funktioniert.
func printMessage (_ message: String) print (message) func printMessage (_ message: String, mit Funktion: (String) -> ()) function (message) let myMessage = "Hallo, Welt!" printMessage (myMessage, mit: printMessage)Das
printMessage (_: with :)
Die Funktion akzeptiert einen String als ersten Parameter und eine Funktion des Typs(String) -> ()
als zweiten Parameter. Im Rumpf der Funktion wird die Funktion, die wir übergeben, mit der Funktion aufgerufenBotschaft
Streit.Das Beispiel zeigt auch, wie wir das aufrufen können
printMessage (_: with :)
Funktion. Dasmeine Nachricht
Die Konstante wird als erstes Argument übergeben und dasprintMessage (_ :)
Funktion als zweites Argument. Wie cool ist das?Funktionen als Rückgabetypen
Es ist auch möglich, eine Funktion von einer Funktion zurückzugeben. Das nächste Beispiel ist ein wenig durchdacht, veranschaulicht aber, wie die Syntax aussieht.
func compute (_ add: Bool) -> (Int, Int) -> Int func add (_ a: Int, _ b: Int) -> Int return a + b func subtrahieren (_ a: Int, _ b: Int) -> Int return a - b wenn der Zusatz return add else return subtract let computeFunction = compute (true) let result = computeFunction (1, 2) print (Ergebnis)Das
berechnen(_:)
function akzeptiert einen booleschen Wert und gibt eine Funktion vom Typ zurück(Int, Int) -> Int
. Dasberechnen(_:)
Funktion enthält zwei verschachtelte Funktionen, die ebenfalls vom Typ sind(Int, Int) -> Int
,hinzufügen(_:_:)
undsubtrahieren(_:_:)
.Das
berechnen(_:)
Die Funktion gibt einen Verweis auf diehinzufügen(_:_:)
oder dersubtrahieren(_:_:)
Funktion, basierend auf dem Wert vonZusatz
Parameter.Das Beispiel zeigt auch, wie Sie das verwenden
berechnen(_:)
Funktion. Wir speichern einen Verweis auf die Funktion, die vom zurückgegeben wirdberechnen(_:)
Funktion in dercomputeFunction
Konstante. Wir rufen dann die in gespeicherte Funktion aufcomputeFunction
, vorbei1
und2
, Speichern Sie das Ergebnis in derErgebnis
konstant und drucken Sie den Wert vonErgebnis
in der Standardausgabe. Das Beispiel mag komplex aussehen, ist aber eigentlich leicht zu verstehen, wenn Sie wissen, was los ist.Fazit
Sie sollten jetzt ein gutes Verständnis dafür haben, wie Funktionen in Swift funktionieren und was Sie damit tun können. Funktionen sind für die Swift-Sprache von grundlegender Bedeutung, und Sie werden sie beim Arbeiten mit Swift ausgiebig verwenden.
Im nächsten Artikel tauchen wir zuerst in Schließungen ein - ein mächtiges Konstrukt, das an Blöcke in C und Objective-C, Schließungen in JavaScript und Lambdas in Ruby erinnert.
Wenn Sie wissen möchten, wie Sie mit Swift 3 echte Apps programmieren können, lesen Sie unseren Kurs Erstellen von iOS-Apps mit Swift 3. Ob Sie nun mit der iOS-App vertraut sind oder ob Sie von Objective-C auf den Wechsel wechseln möchten Natürlich erhalten Sie mit Swift einen Einstieg in die App-Entwicklung.