Swift From Scratch Funksjon Parametre, Typer og Nesting

I forrige artikkel undersøkte vi grunnleggende funksjonene i Swift. Funksjoner har imidlertid mye mer å tilby. I denne artikkelen fortsetter vi utforskningen av funksjoner og ser på funksjonsparametere, nesting og typer.

1. Lokale og eksterne parameternavn

Parameternavn

La oss se på et av eksemplene fra forrige artikkel. De printMessage (melding :) funksjon definerer en parameter, budskap.

func printMessage (melding: String) print (message)

Vi tildeler et navn, budskap, til parameteren og bruk dette navnet når vi ringer til funksjonen.

printMessage (melding: "Hei, verden!")

Men legg merke til at vi også bruker samme navn for å referere til verdien av parameteren i funksjonens kropp.

func printMessage (melding: String) print (message)

I Swift har en parameter alltid a lokal parameternavn, og det har eventuelt en utvendig parameternavn. I eksemplet er de lokale og eksterne parameternavnene identiske.

API-retningslinjer

Fra Swift 3 har Swift-teamet definert et klart sett med API-retningslinjer. Jeg vil ikke gå inn i disse retningslinjene i denne opplæringen, men jeg vil påpeke at definisjonen av printMessage (melding :) Funksjonen avviker fra disse retningslinjene. Navnet på funksjonen inneholder ordet budskap, og parameteren heter også budskap. Med andre ord, gjentar vi oss selv.

Det ville være mer elegant hvis vi kunne påberope seg printMessage (melding :) funksjon uten budskap søkeord. Dette er det jeg har i tankene.

printMessage ("Hei, verden!")

Dette er mulig, og det er mer i tråd med retningslinjene for Swift API. Men hva er forskjellig? Forskjellen er lett å se hvis vi tar en titt på den oppdaterte funksjonsdefinisjonen. Det oppdaterte eksemplet avslører også mer om funksjonalitetens anatomi i Swift.

func printMessage (_ message: String) print (message)

I en funksjonsdefinisjon defineres hver parameter av et eksternt parameternavn, et lokalt parameternavn, et kolon og typen av parameteren. Hvis de lokale og eksterne parameternavnene er identiske, skriver vi bare parameternavnet en gang. Derfor definerer det første eksemplet ett parameternavn, budskap.

Hvis vi ikke vil tildele et eksternt parameternavn til en parameter, bruker vi _, et understrek. Dette informerer kompilatoren om at parameteren ikke har et eksternt parameternavn, og det betyr at vi kan utelate parameternavnet når funksjonen påberopes.

Eksterne parameternavn

Mål-C er kjent for sine lange metodenavn. Selv om dette kan se clunky og inelegant til utenforstående, gjør det metoder enkle å forstå og, hvis det vel velges, veldig beskrivende. Swift-teamet forstod denne fordelen og introduserte eksterne parameternavn fra dag ett.

Når en funksjon aksepterer flere parametere, er det ikke alltid klart hvilket argument som tilsvarer hvilken parameter. Ta en titt på følgende eksempel for å bedre forstå problemet. Legg merke til at parameterne ikke har et eksternt parameternavn.

func power (_a: Int, _b: Int) -> Int var resultat = a for _ i 1 ... 

De makt(_:_:) funksjonen øker verdien av en av eksponenten b. Begge parameterne er av typen int. Mens de fleste vil intuitivt passere basisverdien som det første argumentet og eksponenten som det andre argumentet, er dette ikke klart fra funksjonens type, navn eller signatur. Som vi så i forrige artikkel, er det enkelt å påkalle funksjonen.

kraft (2, 3)

For å unngå forvirring kan vi gi parametere til en funksjon eksterne navn. Vi kan da bruke disse eksterne navnene når funksjonen kalles for entydig å indikere hvilket argument som tilsvarer hvilken parameter. Ta en titt på det oppdaterte eksemplet nedenfor.

func power (base a: Int, eksponent b: Int) -> Int var resultat = a for _ i 1 ... 

Merk at funksjonens kropp ikke har endret seg siden de lokale navnene ikke er endret. Men når vi påberoper den oppdaterte funksjonen, er forskjellen klar og resultatet er mindre forvirrende.

kraft (base: 2, eksponent: 3)

Mens typene av begge funksjonene er identiske, (Int, Int) -> Int, funksjonene er forskjellige. Med andre ord er den andre funksjonen ikke en redeklarasjon av den første funksjonen. Syntaxen for å påkalle den andre funksjonen kan minne deg om Objective-C. Ikke bare er argumentene tydelig beskrevet, men kombinasjonen av funksjon og parameternavn beskriver også formålet med funksjonen.

I noen tilfeller vil du bruke samme navn for det lokale og det eksterne parameternavnet. Dette er mulig, og det er ikke nødvendig å skrive parameternavnet to ganger. I det følgende eksemplet bruker vi utgangspunkt og eksponent som de lokale og eksterne parameternavnene.

func power (base: Int, eksponent: Int) -> Int var resultat = base for _ i 1 ... 

Ved å definere ett navn for hver parameter, tjener parameternavnet som det lokale og eksterne navnet på parameteren. Dette betyr også at vi må oppdatere kroppens funksjon.

Det er viktig å merke seg at ved å gi et eksternt navn til en parameter, er du pålagt å bruke det navnet når du påkaller funksjonen. Dette bringer oss til standardverdier.

Standardverdier

Vi dekket standardparameterverdier i forrige artikkel. Dette er funksjonen vi definerte i den artikkelen.

func printDate (dato: Dato, format: String = "YY / MM / dd") -> String let dateFormatter = DateFormatter () dateFormatter.dateFormat = format returdatoFormatter.string (fra: dato)

Hva skjer hvis vi ikke definerer et eksternt parameternavn for den andre parameteren, som har en standardverdi?

func printDate (dato: Dato, _ format: String = "YY / MM / dd") -> String let dateFormatter = DateFormatter () dateFormatter.dateFormat = formater returdatoFormatter.string (fra: dato)

Kompilatoren ser ikke ut til å bry seg. Men er dette det vi vil ha? Det er best å definere et eksternt parameternavn til valgfrie parametere (parametere med en standardverdi) for å unngå forvirring og tvetydighet.

Legg merke til at vi gjentar oss igjen i det forrige eksempelet. Det er ikke nødvendig å definere et eksternt parameternavn for Dato parameter. Det neste eksemplet viser hva printDate (_: format :) Funksjonen ville se ut hvis vi fulgte retningslinjene for Swift API.

func printDate (_ date: Date, format: String = "YY / MM / dd") -> String let dateFormatter = DateFormatter () dateFormatter.dateFormat = format return dateFormatter.string (fra: date)

Vi kan nå påberope seg formatDate (_: format :) funksjon uten å bruke Dato etikett for den første parameteren og med et valgfritt datoformat.

printDate (Date ()) printDate (Date (), format: "dd / MM / YY")

2. Parametre og mutability

La oss revidere det første eksemplet på denne opplæringen, printMessage (_ :) funksjon. Hva skjer hvis vi endrer verdien av budskap parameter inne i funksjonens kropp?

func printMessage (_ message: String) message = "Skriv ut: \ (melding)" skriv ut (melding)

Det tar ikke lang tid for kompilatoren å begynne å klage.

Parametrene til en funksjon er konstanter. Med andre ord, mens vi får tilgang til verdiene av funksjonsparametere, kan vi ikke endre verdien. For å omgå denne begrensningen, erklærer vi en variabel i funksjonens kropp og bruker den variabelen i stedet.

func printMessage (_ message: String) var melding = message message = "Skriv ut: \ (melding)" print (melding)

3. Variadiske parametere

Mens begrepet kan høres ulikt i begynnelsen, er variadiske parametre vanlige i programmeringen. En variadisk parameter er en parameter som aksepterer null eller flere verdier. Verdiene må være av samme type. Bruke variadiske parametre i Swift er trivielt, som det følgende eksemplet illustrerer.

func sum (_ args: Int ...) -> Int var resultat = 0 for en i args result + = a returresultat sum (1, 2, 3, 4)

Syntaxen er lett å forstå. For å markere en parameter som variadic, legger du til tre punkter til parameterens type. I funksjonen kroppen er variadic parameter tilgjengelig som en matrise. I eksemplet ovenfor, args er en rekke av int verdier.

Fordi Swift trenger å vite hvilke argumenter som samsvarer med hvilke parametere, er det nødvendig med en variadisk parameter som den siste parameteren. Det innebærer også at en funksjon kan ha minst en variadisk parameter.

Ovenstående gjelder også hvis en funksjon har parametere med standardverdier. Den variadiske parameteren skal alltid være den siste parameteren.

4. In-Out Parametre

Tidligere i denne opplæringen lærte du at parametrene til en funksjon er konstanter. Hvis du vil overføre en verdi til en funksjon, endre den i funksjonen, og send den tilbake ut av funksjonen, er utgangsparametre det du trenger.

Følgende eksempel viser et eksempel på hvordan utgående parametere fungerer i Swift og hva syntaksen ser ut.

func prefixString (_ streng: inout String, med prefiks: String) string = prefix + string

Vi definerer den første parameteren som en in-out parameter ved å legge til inout søkeord. Den andre parameteren er en vanlig parameter med et eksternt navn på withString og et lokalt navn på prefiks. Hvordan bruker vi denne funksjonen?

var input = "world!" prefixString (& input, med: "Hei,")

Vi erklærer en variabel, inngang, av type string og send det til prefixString (_: med :) funksjon. Den andre parameteren er en streng bokstavelig. Ved å påkalle funksjonen, verdien av inngang variabel blir Hei Verden!. Merk at det første argumentet er prefiks med en ampersand, &, for å indikere at det er en in-out parameter.

Det står selvsagt at konstanter og bokstaver ikke kan sendes inn som in-out parametere. Kompilatoren kaster en feil når du gjør det som illustrert i de følgende eksemplene.

Det er tydelig at in-out parametere ikke kan ha standardverdier eller være variadiske. Hvis du glemmer disse detaljene, påminner kompilatoren deg med en feil.

5. Nesting

I C og Objective-C kan funksjoner og metoder ikke nestes. I Swift er imidlertid nestede funksjoner ganske vanlige. Funksjonene vi så i denne og forrige artikkel er eksempler på globale funksjoner - de er definert i det globale omfanget.

Når vi definerer en funksjon i en global funksjon, refererer vi til den funksjonen som en nestet funksjon. En nestet funksjon har tilgang til verdiene som er definert i sin omsluttende funksjon. Ta en titt på følgende eksempel for å bedre forstå dette.

func printMessage (_ message: String) la a = "hallo verden" func printHelloWorld () print (a)

Mens funksjonene i dette eksemplet ikke er veldig nyttig, illustrerer de ideen om nestede funksjoner og fanger verdier. De printHelloWorld () funksjonen er bare tilgjengelig fra innsiden av printMessage (_ :) funksjon.

Som illustrert i eksemplet, er printHelloWorld () funksjonen har tilgang til konstanten en. Verdien er fanget av den nestede funksjonen og er derfor tilgjengelig fra den funksjonen. Swift tar seg av å fange verdier, inkludert styring av minnet av disse verdiene.

6. Funksjonstyper

Funksjoner som parametere

I forrige artikkel berørte vi kort funksjonstypene. En funksjon har en bestemt type, som består av funksjonens parametertyper og dens returtype. De printMessage (_ :) funksjonen er for eksempel av typen (String) -> (). Husk at () symboliserer Tomrom, som tilsvarer en tom tuple.

Fordi hver funksjon har en type, er det mulig å definere en funksjon som aksepterer en annen funksjon som en parameter. Følgende eksempel viser hvordan dette virker.

func printMessage (_ message: String) print (message) func printMessage (_ melding: String, med funksjon: (String) -> ()) funksjon (melding) la myMessage = "Hei, verden!" printMessage (minMessage, med: printMessage)

De printMessage (_: med :) funksjonen aksepterer en streng som sin første parameter og en funksjon av typen (String) -> () som sin andre parameter. I funksjonens kropp er funksjonen som vi sender inn, påkalt med budskap argument.

Eksemplet illustrerer også hvordan vi kan påberope seg printMessage (_: med :) funksjon. De myMessage Konstant er sendt inn som det første argumentet og printMessage (_ :) fungere som det andre argumentet. Hvor kult er det?

Funksjoner som returtyper

Det er også mulig å returnere en funksjon fra en funksjon. Det neste eksemplet er litt opptatt, men det illustrerer hva syntaksen ser ut.

func beregne (_ tillegg: Bool) -> (Int, Int) -> Int func add (_ a: Int, _b: Int) -> Int return a + b func subtrahere (_ a: Int, _ b: Int) -> Int return a - b hvis tillegg return add ellers return subtract la computeFunction = compute (true) la resultatet = computeFunction (1, 2) print

De beregn (_ :) funksjonen aksepterer en boolsk og returnerer en funksjon av typen (Int, Int) -> Int. De beregn (_ :) funksjonen inneholder to nestede funksjoner som også er av typen (Int, Int) -> Int, Legg til(_:_:) og trekke fra(_:_:).

De beregn (_ :) funksjonen returnerer en referanse til enten Legg til(_:_:) eller trekke fra(_:_:) funksjon, basert på verdien av addisjon parameter.

Eksemplet viser også hvordan du bruker beregn (_ :) funksjon. Vi lagrer en referanse til funksjonen som returneres av beregn (_ :) fungere i computeFunction konstant. Vi kaller deretter funksjonen som er lagret i computeFunction, passerer inn 1 og 2, lagre resultatet i resultat konstant, og skriv ut verdien av resultat i standardutgangen. Eksemplet kan se komplisert ut, men det er faktisk lett å forstå hvis du vet hva som skjer.

Konklusjon

Du bør nå ha en god forståelse av hvordan funksjoner fungerer i Swift og hva du kan gjøre med dem. Funksjoner er grunnleggende for Swift-språket, og du vil bruke dem mye når du arbeider med Swift.

I den neste artikkelen dykker vi hodet først til lukninger - en kraftig konstruksjon som minner om blokker i C og Objective-C, lukninger i JavaScript og lambdas i Ruby.

Hvis du vil lære hvordan du bruker Swift 3 til å kode sanntidsprogrammer, sjekk ut kurset ditt Opprett IOS Apps With Swift 3. Enten du er ny i iOS app-utvikling eller ønsker å skifte bryteren fra Objective-C, dette kurset vil komme i gang med Swift for app utvikling.