Swift From Scratch Parametri de funcții, tipuri și nesting

În articolul precedent, am explorat elementele de bază ale funcțiilor din Swift. Funcțiile au totuși mult mai multe de oferit. În acest articol, continuăm să explorăm funcțiile și să analizăm parametrii funcției, cuiburile și tipurile.

1. Numele locale și externe ale parametrilor

Numele parametrilor

Să revedem unul dintre exemplele din articolul precedent. printMessage (Mesaj :) funcție definește un parametru, mesaj.

func printMessage (mesaj: String) print (mesaj)

Atribuiți un nume, mesaj, la parametru și folosiți acest nume când sunăm funcția.

printMessage (mesaj: "Bună ziua, lumea!")

Dar observați că folosim același nume pentru a face referire la valoarea parametrului din corpul funcției.

func printMessage (mesaj: String) print (mesaj)

În Swift, un parametru are întotdeauna a local nume de parametru, și opțional are un extern nume de parametru. În exemplu, numele parametrilor locali și externi sunt identici.

Ghidul API

Începând cu Swift 3, echipa Swift a definit un set clar de ghiduri API. Nu voi intra în aceste linii directoare în acest tutorial, dar vreau să subliniez că definiția printMessage (Mesaj :) se abate de la aceste orientări. Numele funcției conține cuvântul mesaj, și parametrul este, de asemenea, numit mesaj. Cu alte cuvinte, ne repetăm.

Ar fi mai elegant dacă am putea invoca printMessage (Mesaj :) funcția fără mesaj cuvinte cheie. Asta am în minte.

printMessage ("Bună ziua, lumea!")

Acest lucru este posibil și este mai în concordanță cu orientările Swift API. Dar ce este diferit? Diferența este ușor de observat dacă analizăm definiția actualizată a funcției. Exemplul actualizat dezvăluie, de asemenea, mai multe despre anatomia funcțiilor din Swift.

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

Într-o definiție a funcției, fiecare parametru este definit de un nume de parametru extern, de un nume de parametru local, de un colon și de tipul parametrului. Dacă numele parametrilor locali și externi sunt identici, scrieți doar numele parametrului o singură dată. Acesta este motivul pentru care primul exemplu definește un nume de parametru, mesaj.

Dacă nu dorim să atribuiți un nume de parametru extern unui parametru, vom folosi _, o subliniere. Aceasta informează compilatorul că parametrul nu are un nume de parametru extern, ceea ce înseamnă că putem să omitem numele parametrului când funcția este invocată.

Nume de parametri externi

Obiectivul-C este cunoscut pentru nume lungi de metode. În timp ce acest lucru poate părea ciudat și inelegant pentru cei din afară, face ca metodele să fie ușor de înțeles și, dacă sunt alese bine, foarte descriptive. Echipa Swift a înțeles acest avantaj și a introdus nume de parametri externi din prima zi.

Atunci când o funcție acceptă mai mulți parametri, nu este întotdeauna evident ce argument corespunde parametrului. Consultați exemplul următor pentru a înțelege mai bine problema. Observați că parametrii nu au un nume de parametru extern.

func func (_ a: Int, _ b: Int) -> Int var rezultat = a pentru _ in 1 ... 

putere(_:_:) funcția ridică valoarea A de exponent b. Ambii parametri sunt de tip Int. În timp ce majoritatea oamenilor vor transmite intuitiv valoarea de bază ca primul argument și exponentul ca al doilea argument, acest lucru nu este clar din tipul, numele sau semnătura funcției. După cum am văzut în articolul precedent, invocarea funcției este simplă.

putere (2, 3)

Pentru a evita confuzia, putem da parametrii unei funcții externe. Apoi, putem folosi aceste nume externe atunci când funcția este chemată să indice fără echivoc ce argument corespunde parametrului. Consultați exemplul actualizat de mai jos.

func func (baza a: Int, exponent b: Int) -> Int var rezultat = a pentru _ in 1 ... 

Rețineți că corpul funcției nu sa schimbat, deoarece numele locale nu s-au schimbat. Cu toate acestea, când invocăm funcția actualizată, diferența este clară și rezultatul este mai puțin confuz.

putere (baza: 2, exponent: 3)

În timp ce tipurile ambelor funcții sunt identice, (Int, Int) -> Int, funcțiile sunt diferite. Cu alte cuvinte, a doua funcție nu este o redeclarare a primei funcții. Sintaxa de invocare a celei de-a doua funcții vă poate aminti de obiectivul C. Nu numai argumentele sunt descrise clar, dar combinația de nume de funcții și parametri descrie de asemenea scopul funcției.

În unele cazuri, doriți să utilizați același nume pentru numele parametrilor locali și externi. Acest lucru este posibil și nu este nevoie să tastați numele parametrului de două ori. În exemplul următor, vom folosi baza și exponent ca nume de parametri locali și externi.

func func (bază: Int, exponent: Int) -> Int var rezultat = bază pentru _ în 1 ... 

Prin definirea unui nume pentru fiecare parametru, numele parametrului servește ca nume local și extern al parametrului. Acest lucru înseamnă, de asemenea, că trebuie să actualizăm corpul funcției.

Este important să rețineți că prin furnizarea unui nume extern pentru un parametru, trebuie să utilizați acest nume atunci când invocați funcția. Acest lucru ne aduce la valorile implicite.

Valori implicite

Am acoperit valori implicite ale parametrilor în articolul precedent. Aceasta este funcția definită în acel articol.

func printDate (data: data, formatul: String = "YY / MM / dd") -> String let dateFormatter = DateFormatter () dateFormatter.dateFormat = format data returnareFormatter.string

Ce se întâmplă dacă nu definim un nume de parametru extern pentru al doilea parametru, care are o valoare implicită?

func printDate (data, data, _ format: String = "YY / MM / dd") -> String date dateFormatter = DateFormatter () dateFormatter.dateFormat = format data returnareFormatter.string

Compilatorul nu pare să aibă grijă. Dar asta este ceea ce vrem? Cel mai bine este să definiți un nume de parametru extern parametrilor opționali (parametrii cu o valoare implicită) pentru a evita confuzia și ambiguitatea.

Observați că ne repetăm ​​din nou în exemplul anterior. Nu este nevoie să definiți un nume de parametru extern pentru Data parametru. Următorul exemplu arată ce printDate (_: Format :) ar arăta dacă am urma regulile Swift API.

func printDate (_ date: data, format: String = "YY / MM / dd") -> String date dateFormatter = DateFormatter () dateFormatter.dateFormat = format data returnareFormatter.string

Putem invoca acum formatDate (_: Format :) fără a utiliza funcția Data eticheta pentru primul parametru și cu un format de dată opțional.

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

2. Parametrii și mobilitatea

Să revedem primul exemplu al acestui tutorial printMessage (_ :) funcţie. Ce se întâmplă dacă schimbăm valoarea mesaj parametru în interiorul corpului funcției?

func printMessage (mesaj: String) message = "Imprimare: \ (mesaj)" print (mesaj)

Nu durează mult până când compilatorul începe să se plângă.

Parametrii unei funcții sunt constante. Cu alte cuvinte, în timp ce putem accesa valorile parametrilor funcției, nu putem schimba valoarea lor. Pentru a rezolva această limitare, declarăm o variabilă în corpul funcției și folosim această variabilă.

func printMessage (mesaj: String) var message = message message = "Imprimare: \ (mesaj)" print (mesaj)

3. Parametrii Variadic

În timp ce termenul poate părea ciudat la început, parametrii variadic sunt obișnuiți în programare. Un parametru variadic este un parametru care acceptă zero sau mai multe valori. Valorile trebuie să fie de același tip. Utilizarea parametrilor variadic în Swift este trivial, după cum ilustrează exemplul următor.

funcția sumă (1, 2, 3, 4) pentru rezultatul întoarcere 

Sintaxa este ușor de înțeles. Pentru a marca un parametru ca variadic, adăugați trei puncte la tipul parametrului. În corpul funcției, parametrul variadic este accesibil ca o matrice. În exemplul de mai sus, args este o serie de Int valorile.

Deoarece Swift trebuie să știe care argumente corespund la care parametri, un parametru variadic trebuie să fie ultimul parametru. De asemenea, aceasta implică faptul că o funcție poate avea cel mult un parametru variadic.

Cele de mai sus se aplică și în cazul în care o funcție are parametri cu valori implicite. Parametrul variadic ar trebui să fie întotdeauna ultimul parametru.

4. Parametri in-out

Mai devreme în acest tutorial, ați aflat că parametrii unei funcții sunt constante. Dacă doriți să treceți o valoare într-o funcție, modificați-o în funcție și scoateți-o afară din funcție, parametrii in-out sunt ceea ce aveți nevoie.

Următorul exemplu prezintă un exemplu de funcționare a parametrilor in-out în Swift și cum arată sintaxa.

func prefixString (_ string: inout String, cu prefix: String) string = prefix + string

Definim primul parametru ca parametru in-out prin adăugarea lui în afară cuvinte cheie. Al doilea parametru este un parametru obișnuit, cu un nume extern de withString și un nume local prefix. Cum invocăm această funcție?

var input = "lumea!" prefixString (& introducere, cu: "Bună ziua")

Vom declara o variabilă, intrare, de tip Şir și trimiteți-l la prefixString (_: cu :) funcţie. Al doilea parametru este un literal șir. Invocând funcția, valoarea lui intrare variabilă devine Salut Lume!. Rețineți că primul argument este prefixat cu un ampersand, &, pentru a indica faptul că este un parametru in-out.

Este de la sine înțeles că constantele și literalii nu pot fi transmise ca parametri in-out. Compilatorul aruncă o eroare atunci când faceți așa cum este ilustrat în exemplele de mai jos.

Este evident că parametrii in-out nu pot avea valori implicite sau pot fi variadic. Dacă uitați aceste detalii, compilatorul vă reamintește cu o eroare.

5. Hrănirea

În C și Obiectiv-C, funcțiile și metodele nu pot fi imbricate. În Swift, totuși, funcțiile imbricate sunt destul de comune. Funcțiile pe care le-am văzut în acest articol și în articolul precedent sunt exemple de funcții globale - acestea sunt definite în domeniul global.

Când definim o funcție în interiorul unei funcții globale, ne referim la acea funcție ca la o funcție imbricată. O funcție imbricată are acces la valorile definite în funcția de închidere. Uitați-vă la următorul exemplu pentru a înțelege mai bine acest lucru.

func printMessage (mesaj: String) let a = "salut lume" func printHelloWorld () print (a)

În timp ce funcțiile din acest exemplu nu sunt extrem de utile, ele ilustrează ideea funcțiilor imbricate și valorilor de captare. printHelloWorld () funcția este accesibilă numai din interiorul printMessage (_ :) funcţie.

Așa cum este ilustrat în exemplul nr printHelloWorld () funcția are acces la constanta A. Valoarea este captată de funcția imbricată și, prin urmare, este accesibilă din interiorul acelei funcții. Swift se ocupă de captarea valorilor, inclusiv gestionarea memoriei acestor valori.

6. Tipuri de funcții

Funcționează ca parametru

În articolul precedent, am abordat pe scurt tipurile de funcții. O funcție are un anumit tip, compus din tipurile de parametri ale funcției și tipul lor de returnare. printMessage (_ :) funcția, de exemplu, este de tip (String) -> (). Sa nu uiti asta () simbolizeaza neavenit, care este echivalentă cu o nucă goală.

Deoarece fiecare funcție are un tip, este posibil să se definească o funcție care acceptă o altă funcție ca parametru. Următorul exemplu arată cum funcționează acest lucru.

func printMessage (mesaj: String) print (message) func printMessage (_ mesaj: String, cu functie: (String) -> ()) function (message) myMessage = "Buna! printMessage (mesajul meu, cu: printMessage)

 printMessage (_: cu :) funcția acceptă un șir ca prim parametru și o funcție de tip (String) -> () ca al doilea parametru. În corpul funcției, funcția prin care trecem este invocată cu mesaj argument.

Exemplul ilustrează de asemenea modul în care putem invoca printMessage (_: cu :) funcţie. mesajul meu constanta este trecută ca primul argument și printMessage (_ :) funcția ca al doilea argument. Cat de tare e asta?

Funcționează ca tip de retur

De asemenea, este posibil să returnați o funcție dintr-o funcție. Următorul exemplu este un pic contrived, dar ilustrează cum arată sintaxa.

(int: int, int) -> int (int: int); int (int: b: Int) -> Int return a - b dacă adăugați return add else return subtract let computeFunction = calculate (true) let result = computeFunction (1,

calcula(_:) funcția acceptă un boolean și returnează o funcție de tip (Int, Int) -> Int. calcula(_:) funcția conține două funcții imbricate care sunt, de asemenea, de tip (Int, Int) -> Int, adăuga(_:_:) și scădea(_:_:).

calcula(_:) funcția returnează o referință fie la adăuga(_:_:) sau scădea(_:_:) funcție, pe baza valorii plus parametru.

Exemplul arată, de asemenea, cum se utilizează calcula(_:) funcţie. Pastram o referinta la functia returnata de catre calcula(_:) funcția în computeFunction constant. Apoi invocăm funcția stocată în computeFunction, trecerea 1 și 2, stocați rezultatul în rezultat constantă și tipăriți valoarea rezultat în ieșirea standard. Exemplul poate părea complex, dar este de fapt ușor de înțeles dacă știți ce se întâmplă.

Concluzie

Acum ar trebui să înțelegeți cum funcționează funcțiile Swift și ce puteți face cu ei. Funcțiile sunt fundamentale pentru limbajul Swift și le veți folosi pe scară largă atunci când lucrați cu Swift.

În articolul următor, ne vom arunca cu capul mai întâi în închideri - un construct puternic care amintește de blocuri în C și Obiectiv-C, închideri în JavaScript și lambdas în Ruby.

Dacă doriți să aflați cum să utilizați aplicația Swift 3 pentru a codifica aplicațiile din lumea reală, consultați cursul nostru Creați aplicații iOS cu Swift 3. Indiferent dacă sunteți nou în dezvoltarea de aplicații iOS sau căutați să treceți de la obiectivul C, curs va începe cu Swift pentru dezvoltarea de aplicații. 

 


Cod