In het vorige artikel hebben we de basis van functies in Swift onderzocht. Functies hebben echter nog veel meer te bieden. In dit artikel gaan we verder met het verkennen van functies en kijken we naar functieparameters, nesten en typen.
Laten we een van de voorbeelden uit het vorige artikel opnieuw bekijken. De printMessage (message :)
functie definieert één parameter, bericht
.
func printMessage (bericht: String) print (bericht)
We wijzen een naam toe, bericht
, naar de parameter en gebruik deze naam wanneer we de functie aanroepen.
printMessage (bericht: "Hallo wereld!")
Maar merk op dat we ook dezelfde naam gebruiken om te verwijzen naar de waarde van de parameter in de hoofdtekst van de functie.
func printMessage (bericht: String) print (bericht)
In Swift heeft een parameter altijd een lokaal parameternaam, en deze heeft optioneel een extern parameternaam. In het voorbeeld zijn de lokale en externe parameternamen identiek.
Vanaf Swift 3 heeft het Swift-team een duidelijke set API-richtlijnen gedefinieerd. Ik zal in deze tutorial niet ingaan op die richtlijnen, maar ik wil erop wijzen dat de definitie van de printMessage (message :)
functie wijkt af van die richtlijnen. De naam van de functie bevat het woord bericht
, en de parameter heeft ook een naam bericht
. Met andere woorden, we herhalen onszelf.
Het zou eleganter zijn als we de printMessage (message :)
functioneren zonder de bericht
trefwoord. Dit is wat ik in gedachten heb.
printMessage ("Hallo, wereld!")
Dit is mogelijk en het is meer in lijn met de Swift API-richtlijnen. Maar wat is anders? Het verschil is gemakkelijk te herkennen als we de bijgewerkte functiedefinitie bekijken. Het bijgewerkte voorbeeld onthult ook meer informatie over de anatomie van functies in Swift.
func printMessage (_ message: String) print (bericht)
In een functiedefinitie wordt elke parameter gedefinieerd door een externe parameternaam, een lokale parameternaam, een dubbele punt en het type parameter. Als de lokale en externe parameternamen identiek zijn, schrijven we de parameternaam slechts eenmaal. Daarom definieert het eerste voorbeeld één parameternaam, bericht
.
Als we geen externe parameternaam aan een parameter willen toewijzen, gebruiken we de _
, een onderstrepingsteken. Dit informeert de compiler dat de parameter geen externe parameternaam heeft, en dat betekent dat we de parameternaam kunnen weglaten wanneer de functie wordt aangeroepen.
Objective-C staat bekend om zijn lange methode namen. Hoewel dit misschien onhandig en onelegant lijkt voor buitenstaanders, maakt het methoden gemakkelijk te begrijpen en, indien goed gekozen, zeer beschrijvend. Het Swift-team begreep dit voordeel en introduceerde vanaf de eerste dag externe parameternamen.
Wanneer een functie verschillende parameters accepteert, is het niet altijd duidelijk welk argument overeenkomt met welke parameter. Bekijk het volgende voorbeeld om het probleem beter te begrijpen. Merk op dat de parameters geen externe parameternaam hebben.
func power (_ a: Int, _ b: Int) -> Int var result = a for _ in 1 ...De
vermogen (_: _ :)
functie verhoogt de waarde vaneen
door de exponentb
. Beide parameters zijn van het typeInt
. Hoewel de meeste mensen intuïtief de basiswaarde doorgeven als het eerste argument en de exponent als het tweede argument, is dit niet duidelijk uit het type, de naam of de handtekening van de functie. Zoals we in het vorige artikel zagen, is het aanroepen van de functie eenvoudig.vermogen (2, 3)Om verwarring te voorkomen, kunnen we de parameters van een functie externe namen geven. We kunnen dan deze externe namen gebruiken als de functie wordt aangeroepen om ondubbelzinnig aan te geven welk argument overeenkomt met welke parameter. Bekijk het bijgewerkte voorbeeld hieronder.
func power (base a: Int, exponent b: Int) -> Int var result = a for _ in 1 ...Merk op dat de body van de functie niet is gewijzigd sinds de lokale namen niet zijn gewijzigd. Wanneer we echter de bijgewerkte functie aanroepen, is het verschil duidelijk en het resultaat is minder verwarrend.
vermogen (basis: 2, exponent: 3)Hoewel de typen van beide functies identiek zijn,
(Int, Int) -> Int
, de functies zijn anders. Met andere woorden, de tweede functie is geen herclaratie van de eerste functie. De syntaxis om de tweede functie aan te roepen, kan u herinneren aan Objective-C. Niet alleen zijn de argumenten duidelijk beschreven, maar de combinatie van functie- en parameternamen beschrijft ook het doel van de functie.In sommige gevallen wilt u dezelfde naam gebruiken voor de lokale en de externe parameternaam. Dit is mogelijk en het is niet nodig om de parameternaam tweemaal in te voeren. In het volgende voorbeeld gebruiken we
baseren
enexponent
als de lokale en externe parameternamen.func power (basis: Int, exponent: Int) -> Int var result = base for _ in 1 ...Door voor elke parameter één naam te definiëren, dient de parameternaam als de lokale en externe naam van de parameter. Dit betekent ook dat we de hoofdtekst van de functie moeten bijwerken.
Het is belangrijk om op te merken dat door een externe naam voor een parameter op te geven, u verplicht bent om die naam te gebruiken bij het oproepen van de functie. Dit brengt ons naar standaardwaarden.
Standaard waarden
We hebben standaard parameterwaarden in het vorige artikel besproken. Dit is de functie die we in dat artikel hebben gedefinieerd.
func printDate (datum: Datum, formaat: String = "YY / MM / dd") -> String let dateFormatter = DateFormatter () dateFormatter.dateFormat = format return dateFormatter.string (from: date)Wat gebeurt er als we geen externe parameternaam definiëren voor de tweede parameter, die een standaardwaarde heeft?
func printDate (datum: Date, _ format: String = "YY / MM / dd") -> String let dateFormatter = DateFormatter () dateFormatter.dateFormat = format return dateFormatter.string (from: date)Het lijkt de compiler niet uit te maken. Maar is dit wat we willen? Het is het beste om een externe parameternaam te definiëren voor optionele parameters (parameters met een standaardwaarde) om verwarring en dubbelzinnigheid te voorkomen.
Merk op dat we onszelf opnieuw herhalen in het vorige voorbeeld. Het is niet nodig om een externe parameternaam te definiëren voor de
datum
parameter. Het volgende voorbeeld laat zien wat dePrintDate (_: format :)
functie zou eruit zien als we de Swift API-richtlijnen zouden volgen.func printDate (_ date: Date, format: String = "YY / MM / dd") -> String let dateFormatter = DateFormatter () dateFormatter.dateFormat = format return dateFormatter.string (from: date)We kunnen nu het
formatDate (_: format :)
functie zonder dedatum
label voor de eerste parameter en met een optioneel datumformaat.printDate (Datum ()) printDate (Datum (), formaat: "dd / MM / YY")2. Parameters en veranderlijkheid
Laten we het eerste voorbeeld van deze tutorial opnieuw bekijken, de
printMessage (_ :)
functie. Wat gebeurt er als we de waarde van debericht
parameter in de body van de functie?func printMessage (_ message: String) message = "Afdrukken: \ (bericht)" afdrukken (bericht)Het duurt niet lang voordat de compiler begint te klagen.
De parameters van een functie zijn constanten. Met andere woorden, hoewel we toegang hebben tot de waarden van functieparameters, kunnen we hun waarde niet veranderen. Om deze beperking te omzeilen, declareren we een variabele in het lichaam van de functie en gebruiken die variabele in plaats daarvan.
func printMessage (_ message: String) var message = message message = "Afdrukken: \ (bericht)" afdrukken (bericht)3. Variadische parameters
Hoewel de term in het begin misschien vreemd klinkt, zijn variadische parameters gebruikelijk bij het programmeren. Een variadische parameter is een parameter die nul of meer waarden accepteert. De waarden moeten van hetzelfde type zijn. Het gebruik van variadische parameters in Swift is triviaal, zoals het volgende voorbeeld illustreert.
func sum (_ args: Int ...) -> Int var result = 0 for a in args result + = a return result sum (1, 2, 3, 4)De syntaxis is gemakkelijk te begrijpen. Als u een parameter als variabel wilt markeren, voegt u drie punten toe aan het type van de parameter. In de hoofdtekst van de functie is de variadische parameter toegankelijk als een array. In het bovenstaande voorbeeld,
args
is een array vanInt
waarden.Omdat Swift moet weten welke argumenten overeenkomen met welke parameters, is een variadische parameter vereist om de laatste parameter te zijn. Het impliceert ook dat een functie maximaal één variadische parameter kan hebben.
Het bovenstaande is ook van toepassing als een functie parameters heeft met standaardwaarden. De variadische parameter moet altijd de laatste parameter zijn.
4. In-outparameters
Eerder in deze tutorial leerde je dat de parameters van een functie constanten zijn. Als u een waarde wilt doorgeven aan een functie, deze in de functie wilt wijzigen en deze uit de functie wilt overbrengen, zijn in-out parameters wat u nodig hebt.
In het volgende voorbeeld ziet u een voorbeeld van hoe in-out-parameters in Swift werken en hoe de syntaxis eruit ziet.
func prefixString (_ string: inout String, met voorvoegsel: String) string = prefix + stringWe definiëren de eerste parameter als een in-uit parameter door het toevoegen van de
in uit
trefwoord. De tweede parameter is een normale parameter met een externe naam vanwithstring
en een lokale naam vanvoorvoegsel
. Hoe roepen we deze functie aan??var input = "world!" prefixString (& input, met: "Hallo,")We verklaren een variabele,
invoer
, van typeDraad
en geef het door aan deprefixString (_: met :)
functie. De tweede parameter is een letterlijke tekenreeks. Door de functie aan te roepen, de waarde van deinvoer
variabele wordtHallo Wereld!
. Merk op dat het eerste argument voorafgegaan wordt door een ampersand,&
, om aan te geven dat het een in-uit parameter is.Het spreekt voor zich dat constanten en letterlijke waarden niet kunnen worden doorgegeven als in-out parameters. De compiler genereert een foutmelding wanneer u dit doet, zoals in de volgende voorbeelden wordt geïllustreerd.
Het is duidelijk dat in-out parameters geen standaardwaarden kunnen hebben of variadisch zijn. Als u deze details vergeet, herinnert de compiler u vriendelijk aan een fout.
5. Nesten
In C en Objective-C kunnen functies en methoden niet worden genest. In Swift zijn geneste functies echter vrij gebruikelijk. De functies die we in dit en het vorige artikel hebben gezien, zijn voorbeelden van algemene functies: ze zijn gedefinieerd in de globale reikwijdte.
Wanneer we een functie definiëren binnen een globale functie, verwijzen we naar die functie als een geneste functie. Een geneste functie heeft toegang tot de waarden die zijn gedefinieerd in de bijbehorende functie. Bekijk het volgende voorbeeld om dit beter te begrijpen.
func printMessage (_ message: String) let a = "hallo wereld" func printHelloWorld () print (a)Hoewel de functies in dit voorbeeld niet erg nuttig zijn, illustreren ze het idee van geneste functies en het vastleggen van waarden. De
printHelloWorld ()
functie is alleen toegankelijk vanuit deprintMessage (_ :)
functie.Zoals geïllustreerd in het voorbeeld, de
printHelloWorld ()
functie heeft toegang tot de constanteeen
. De waarde wordt vastgelegd door de geneste functie en is daarom toegankelijk vanuit die functie. Swift zorgt voor het vastleggen van waarden, inclusief het beheren van het geheugen van die waarden.6. Functietypen
Functies als parameters
In het vorige artikel hebben we kort ingegaan op functietypen. Een functie heeft een bepaald type, samengesteld uit de parametertypen van de functie en het retourneringstype. De
printMessage (_ :)
de functie is bijvoorbeeld van het type(String) -> ()
. Onthoudt dat()
symboliseertleegte
, wat overeenkomt met een lege tuple.Omdat elke functie een type heeft, is het mogelijk om een functie te definiëren die een andere functie als parameter accepteert. Het volgende voorbeeld laat zien hoe dit werkt.
func printMessage (_ message: String) print (bericht) func printMessage (_ message: String, with function: (String) -> ()) function (message) let myMessage = "Hallo, wereld!" printMessage (mijnMessage, met: printMessage)De
printMessage (_: met :)
functie accepteert een string als zijn eerste parameter en een functie van het type(String) -> ()
als zijn tweede parameter. In het lichaam van de functie wordt de functie die we doorgeven opgeroepen met debericht
argument.Het voorbeeld illustreert ook hoe we het kunnen oproepen
printMessage (_: met :)
functie. Demijn bericht
constante wordt doorgegeven als het eerste argument en deprintMessage (_ :)
fungeren als het tweede argument. Hoe cool is dat?Functies als retourtypen
Het is ook mogelijk om een functie uit een functie te retourneren. Het volgende voorbeeld is een beetje gekunsteld, maar het illustreert hoe de syntaxis eruit ziet.
func compute (_ toevoeging: Bool) -> (Int, Int) -> Int func add (_ a: Int, _ b: Int) -> Int return a + b func subtract (_ a: Int, _ b: Int) -> Int return a - b als optellen retourneren else retourneren aftrekken laat computeFunction = berekenen (true) laat resultaat = computeFunction (1, 2) afdrukken (resultaat)De
berekenen(_:)
function accepteert een boolean en retourneert een functie van het type(Int, Int) -> Int
. Deberekenen(_:)
functie bevat twee geneste functies die ook van het type zijn(Int, Int) -> Int
,toevoegen(_:_:)
enaftrekken(_:_:)
.De
berekenen(_:)
functie geeft een verwijzing naar detoevoegen(_:_:)
of deaftrekken(_:_:)
functie, gebaseerd op de waarde van detoevoeging
parameter.Het voorbeeld laat ook zien hoe u de
berekenen(_:)
functie. We slaan een verwijzing op naar de functie die wordt geretourneerd door deberekenen(_:)
functie in decomputeFunction
constante. Vervolgens roepen we de functie op die is opgeslagen incomputeFunction
, binnenkomen1
en2
, sla het resultaat op in deresultaat
constant en druk de waarde af vanresultaat
in de standaarduitvoer. Het voorbeeld kan er ingewikkeld uitzien, maar het is eigenlijk eenvoudig te begrijpen als u weet wat er aan de hand is.Conclusie
U zou nu een goed begrip moeten hebben van hoe functies in Swift werken en wat u ermee kunt doen. Functies zijn fundamenteel voor de Swift-taal en u zult ze veel gebruiken bij het werken met Swift.
In het volgende artikel duiken we eerst in closures - een krachtige constructie die doet denken aan blokken in C en Objective-C, sluitingen in JavaScript en lambda's in Ruby.
Als je wilt leren hoe je Swift 3 kunt gebruiken om real-world apps te coderen, bekijk dan onze cursus Maak iOS-apps met Swift 3. Of je nu nieuw bent bij de ontwikkeling van iOS-apps of op zoek bent naar de overstap van Objective-C, deze Natuurlijk begin je met Swift voor app-ontwikkeling.