Enumerații – de obicei le numim "enum"-uri – îți oferă posibilitatea de a-ți defini propriile tale tipuri valori în Swift. În unele limbaje de programare sunt lucruri simple, dar Swift le adaugă o cantiate incredibilă de putere dacă vrei mai mult decât lucrurile de bază.
Să începem cu un exemplu simplu de mai devreme:
func getHaterStatus(weather: String) -> String? {
if weather == "sunny" {
return nil
} else {
return "Hate"
}
}
Această funcție acceptă un string care definește tipul vremii de acum. Problema este că, un string nu este o decizie bună pentru acel tip de date – este "rain", "rainy" sau "raining"? Sau poate "showering", "drizzly" sau "stormy"? Mai rău, ce se întâmplă dacă o persoană scrie "Rain" cu R mare și altcineva scrie "Ran" pentru că nu se uita atunci când scria?
Enum-urile rezolvă această problemă lăsându-te să definești un nou tip, care definește variabilele posibile pe care le poate ține. De exemplu, am putea spune că există cinci tipuri de vreme: soare, nori, ploaie, vânt și zăpadă. Dacă le scriem într-un enum, înseamnă că Swift va accepta doar acele cinci valori – orice altceva va declanșa o eroare. Iar de obicei în spate enum-urile sunt doar numere, care sunt mult mai rapide atunci când lucrezi cu ele decât string-urile.
Să punem asta în cod:
enum WeatherType {
case sun, cloud, rain, wind, snow
}
func getHaterStatus(weather: WeatherType) -> String? {
if weather == WeatherType.sun {
return nil
} else {
return "Hate"
}
}
getHaterStatus(weather: WeatherType.cloud)
Uită-te la primele trei linii: linia 1 dă un nume tipului nostru, WeatherType
. Asta vei folosi în loc de String
sau Int
în codul tău. Linia 2 definește cele cinci cazuri posibile pe care le poate avea enum-ul, așa cum am subliniat mai devreme. Convențional ele încep cu litere mici, deci "sun", "cloud" ș.a. Iar linia 3 este doar o acoladă închisă, care incheie enum-ul.
Acum hai să ne uităm cum este folosit: Am modificat getHaterStatus()
altfel încât să accepte o valoare de tip WeatherType
. Declarația condiționată est de asemenea rescrisă să fie comparată cu WeatherType.sun
, care este valoarea noastră. Amintește-ți, această verificare este doar un număr în spate, ceea ce este foarte rapid.
Acum, mai citește codul odată, pentru că sunt pe cale să-l rescriu făcând două modificări importante. Ești pregătit?
enum WeatherType {
case sun
case cloud
case rain
case wind
case snow
}
func getHaterStatus(weather: WeatherType) -> String? {
if weather == .sun {
return nil
} else {
return "Hate"
}
}
getHaterStatus(weather: .cloud)
Am făcut două modificări. Prima, fiecare tip de vreme se află acum pe propria linie. Poate pare o schimbare minoră, și într-adevăr în acest exemplu este, dar va deveni importantp curând. Cea de-a doua modificare este că am scris if weather == .sun
– nu trebuia să scriu tipul în mod specific WeatherType.sun
deoarece Swift știe că eu compar cu o variabilă de tipul WeatherType
, deci folosește deducere de tip.
Enum-urile sunt folositoare în special în blocurile switch/case
, deoarece Swift cunoaște deja toate valorile pe care enum-ul le poate avea pentru a se asigura că toate sunt acoperite. De exemplu, am putea încerca să rescriem funcția getHaterStatus()
în felul acesta:
func getHaterStatus(weather: WeatherType) -> String? {
switch weather {
case .sun:
return nil
case .cloud, .wind:
return "dislike"
case .rain:
return "hate"
}
}
Da, îmi dau seama că "haters gonna dislike" nu este o lirică extraordinară, dar este în orice caz academic deoarece codul nu va buildui: nu ia în considerare cazul .snow
, și Swift dorește ca toate cazurile să fie acoperite. Trebuie să adaugi un caz pentru el sau să adaugi cazul default.
Unul dintre cele mai puternice proprietăți Swift este că enumerațiile pot avea valori atașate pe care tu le definești. Pentru a extinde exemplul nostru dubios, voi adăuga o valoare cazului .wind
astfel încât să putem specifica cât de tare bate vântul. Modifică codul astfel:
enum WeatherType {
case sun
case cloud
case rain
case wind(speed: Int)
case snow
}
După cum poți vedea, celelalte valori nu necesită o valoare viteză – am pus-o doar la wind
. Acum logia adevărată: Swift ne lasă să adăugăm condiții extra blocului switch/case
astfel încât un caz se va potrivi doar dacă acele condiții sunt îndeplinite. Aceasta folosește cuvântul cheie let
pentru a accesa o valoare din interiorul cazului, apoi cuvântul cheie where
pentru potrivirea modelului.
Aici noua funcție:
func getHaterStatus(weather: WeatherType) -> String? {
switch weather {
case .sun:
return nil
case .wind(let speed) where speed < 10:
return "meh"
case .cloud, .wind:
return "dislike"
case .rain, .snow:
return "hate"
}
}
getHaterStatus(weather: WeatherType.wind(speed: 5))
Poți vedea că .wind
apare de două ori, dar prima oară este adevărat pentru că vântul bate mai încet de 10 kilometrii pe oră. Dacă vântul bate cu 10 sau mai mult, nu se va potrivi. Cheia este să folosești let
pentru a obține valoarea din interiorul enum-ului (pentru a declara un nume de constantă pe care îl poți referenția) apoi folosește condiția where
pentru a verifica.
Swift evaluează switch/case
de la cap la coadă, și se oprește de îndată ce găsește o potrivire. Asta înseamnă că dacă case .cloud, .wind:
apare înainte de case .wind(let speed) where speed < 10:
atunci acela va fi executat – și rezultatul final se schimbă.
Deci, gândește-te atent cum ordonezi cazurile!
Sfat: În Swift opționalele sunt implementate folosind enum-uri cu valori asociate. Există doup cazuri: none
, și some
, cu some
având orice valoare care se află în interiorul opționalului.
SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.
Link copied to your pasteboard.