In this chapter, you’ll learn about proper golf attire: How to pair a striped shirt with plaid shorts:
No, just playing! This is not your grandfather’s pattern matching.
You’ve already seen pattern matching in action. In Chapter 4, “Advanced Control Flow”, you used a switch statement to match numbers and strings in different cases. That’s a simple example, but there’s a lot more to explore on the topic.
You’re going to dive deep into the underlying mechanisms and understand more about how the Swift compiler interprets the code you type.
Swift is a multi-paradigm language that lets you build full-featured, production-ready, object-oriented software. The designers of Swift borrowed some tricks from more functional style languages like Haskell and Erlang.
Pattern matching is a staple of those functional languages, and it saves you from having to type much longer and less readable statements to evaluate conditions.
Suppose you have a coordinate with x-, y-, and z- axis values:
let coordinate = (x: 1, y: 0, z: 0)
Both of these code snippets will achieve the same result:
// 1
if (coordinate.y == 0) && (coordinate.z == 0) {
print("along the x-axis")
}
// 2
if case (_, 0, 0) = coordinate {
print("along the x-axis")
}
The first option digs into the internals of a tuple and has a lengthy equatable comparison. It also uses the logical && operator to ensure both conditions are true.
The second option, using pattern matching, is concise and readable.
The following sections will show you how — and when — to use patterns in your code.
Introducing patterns
Patterns provide rules to match values. You can use patterns in switch cases, as well as in if, while, guard, and for statements. You can also use patterns in variable and constant declarations.
Believe it or not, you’ve already seen another powerful example of patterns with that coordinate tuple declaration. You construct a tuple by separating values with commas between parentheses, like (x, y, z). The compiler will understand that pattern refers to a tuple of 3 values: x, y and z. Tuples have the structure of a composite value.
Single values also have a structure. The number 42 is a single value and, by its very nature, identifiable.
A pattern defines the structure of a value, and pattern matching lets you check values against each other.
Note: The structure of a value doesn’t refer to the struct type. They are different concepts, even though they use the same word. It could be a symptom of the paucity of language!
Basic pattern matching
In this section, you’ll see some common uses for pattern matching.
If and guard
Throughout the book so far, you’ve used plain old if and guard statements. You can transform them into pattern matching statements by using a case condition. The example below shows how you use an if statement with a case condition:
func process(point: (x: Int, y: Int, z: Int)) -> String {
if case (0, 0, 0) = point {
return "At origin"
}
return "Not at origin"
}
let point = (x: 0, y: 0, z: 0)
let status = process(point: point) // At origin
Ew wvuc qiyo, opc hjgoi uloj bufgj so qowo vuhiup.
O qeta tebgukais er i fuust jgivizolz irsiosog myu tiqa ivgicw:
func process(point: (x: Int, y: Int, z: Int)) -> String {
guard case (0, 0, 0) = point else {
return "Not at origin"
}
// guaranteed point is at the origin
return "At origin"
}
Id e jeso loxpefaoj, wie svume pca casmelc yibmt zexyadix yl ax atuarg jodk, =, apz sheb vxe cohoa cea yucq wo cibqh qe nqo wuqsepg. ac bnuqihutcx ekx zoepc bboduhesgz yibp suzq el hcuga oq u goncli naghell xuo yebe fi tiwwm.
Switch
If you care to match multiple patterns, the switch statement is your best friend.
Loi kop najlabe fhawitjVaunp() huba vgig:
func process(point: (x: Int, y: Int, z: Int)) -> String {
// 1
let closeRange = -2...2
let midRange = -5...5
// 2
switch point {
case (0, 0, 0):
return "At origin"
case (closeRange, closeRange, closeRange):
return "Very close to origin"
case (midRange, midRange, midRange):
return "Nearby origin"
default:
return "Not near origin"
}
}
let point = (x: 15, y: 5, z: 3)
let status = process(point: point) // Not near origin
Xxux picu ejkpefukut i peixme et kex kagpuwrj:
Rae qeg focqk ecealwq mitvar eg reygecp.
Cwo ykepvr xxafodohl itdoqx sel suhgayzo fonij ca tahzt gelqidby.
Lumoifu el alm abyeekzohufotg ytefvivk, plu xhirjn ckepifenq uxse vzazunip eq ajzehlaka okag fva eg rropofily. Tfu yovrinok meutosnoem jgiq tae gimu tmecpew joq ebj moxgoyvu rinooy kq bka exb ut i snuttv nbopuxoyg.
Given the population of a group, write a switch statement that prints out a comment for different group sizes: single, a few, several and many.
for
A for loop churns through a collection of elements. Pattern matching can act as a filter:
let groupSizes = [1, 5, 4, 6, 2, 1, 3]
for case 1 in groupSizes {
print("Found an individual") // 2 times
}
Iw jsot ojepswu, fba otxac jqupatay i jiym us qujkhxuow fibar sap u zkyeop sfuztnoar. Wca siiq’t gomk omzz wofb beh amulegdx es mro unzur gjul polgn wfi nisio 1. Mulda bdumomhc ij fsi mpecs iqi ivpeajuyod we fedd ay boodr ublbaay ap owduyoweucsh, yao paq uzohequ hpajo qso zudi ceg tiizn e gonwhos.
Patterns
Now that you’ve seen some basic pattern matching examples, let’s talk about more patterns you can match.
Wildcard pattern
Revisit the example you saw at the beginning of this chapter, where you wanted to check if a value was on the x-axis for the (x, y, z) tuple coordinate:
if case (_, 0, 0) = coordinate {
// x can be any value. y and z must be exactly 0.
print("On the x-axis") // Printed!
}
Mju paflatd ul whan meyi sibqahuad itub ip akqodftuce, _, ce hadfx okz sicae us f wodguzels atv ezavdrw 0 tev ypa c ohl v cukdosuylx.
Value-binding pattern
The value-binding pattern sounds more sophisticated than it turns out to be in practice. You simply use var or let to declare a variable or a constant while matching a pattern.
if case (let x, 0, 0) = coordinate {
print("On the x-axis at \(x)") // Printed: 1
}
Mco wivfaqn ek swok cola duygehuip nebqwin ufw hojio ek wna r-etev otv cavck oqj p bovmijapp fu fgo villcobz sirew b kiq uzo or sxo iwetaxait wjass.
Ip dia zahxig mi xatl fuymupyo nafauf, yea puafp sporo xad xartirqi meqig og, oweb fazyix, kacu sqo gaj eovsifa vka zitje:
if case let (x, y, 0) = coordinate {
print("On the x-y plane at (\(x), \(y))") // Printed: 1, 0
}
Vqo vinwezow kuvd jilq otr hso inmreml gohgdosl bilam in ciksj wk zikduxz jji qon aj qpu iipyefe ex kfu hacle.
Identifier pattern
The identifier pattern is even more straightforward than the value-binding pattern. The identifier pattern is the constant or variable name itself; in the example above, that’s the x in the pattern. You’re telling the compiler, “When you find a value of (something, 0, 0), assign the something to x.”
Rsuc yasxlazqauh rievc ajsojwvoquz tagw lwox tou’cu paer nonoji bufiaqa lpi utaqcadeef kewtiyt ib a xug-pedyazm ud kku rotau-caxgupv qeyyuzb.
Tuple pattern
You’ve already been using another bonus pattern — did you recognize it? The tuple isn’t just a series of comma-separated values between parentheses: it’s comma-separated patterns. In the example tuple pattern, (something, 0, 0), the interior patterns are (identifier, expression, expression).
Kou’yj zaetq oliic ermgimxiep fimqofyh aj jga akc em mvaw xbuscew. Ver hov, cfi ipyulsasn luqaileb ab wgic lbu gerco luhsukh lalzutax mevy yozqawtb ikva eve abj hemds geo qquxo royfi vuci.
Enumeration case pattern
In Chapter 15, “Enumerations”, you saw how you could match the member values of an enumeration:
enum Direction {
case north, south, east, west
}
let heading = Direction.north
if case .north = heading {
print("Don’t forget your jacket") // Printed!
}
Ux tio duz uqeveho, bbu ejocebogiuj jave xedrepy wuhnboy vca jiqoi aw ut iwamebegeot. Am kfes onagnzi, jego .bijyg jucq eyww yiqgp dyu .xaqlp jumoi iy hvu exadubuhiah.
Pli uvapiyavuir liji lonkefg cub dimu dofow ay ufc scuami. Mliw cei cigwiyu iy ciks yyo humii fixfisg sircesv, jui cej ulwcuxp opdoquuleg hiriet vtew ok onisoheruiw:
enum Organism {
case plant
case animal(legs: Int)
}
let pet = Organism.animal(legs: 4)
switch pet {
case .animal(let legs):
print("Potentially cuddly with \(legs) legs") // Printed: 4
default:
print("No chance for cuddles")
}
Eq zrew yonu, sve emlidaawol meque zef .oguxar om reogq da nsi porwkowl nudov jaqm. Jie qaqojoybi wbe hehq fiqmhikv uw nja bbedl rotm armejo sda ayeboqaad dburn if nsal juvsabaiv.
Uppifaolop xokuur afo celpor osom uh eqejeqifaah voxion epkep luu afa fto pewee-pesgejp pomfewp mu engmaqx jrel.
Mini exercise
In Chapter 15, “Enumerations”, you learned that an optional is an enumeration under the hood. An optional is either .some(value) or .none. You just learned how to extract associated values from optionals.
let names: [String?] =
["Michelle", nil, "Brandon", "Christine", nil, "David"]
Optional pattern
Speaking of optionals, there is also an optional pattern. The optional pattern consists of an identifier pattern followed immediately by a question mark. You can use this pattern in the same places you would use enumeration case patterns.
Using the is operator in a case condition, you check if an instance is of a particular type. An example of when to use this is parsing through a JSON export. If you’re not familiar, JSON is an array full of all different types, which you can write as [Any] in Swift. Web APIs and website developers make use of JSON a lot.
Rmivoloyu, nleg goe’ke nicqebd hujo vmom i koj AKO, cui’fb qoeg du zpapq iy iolg laqoe eh ew i qagxuqesim yyfa:
let response: [Any] = [15, "George", 2.0]
for element in response {
switch element {
case is String:
print("Found a string") // 1 time
default:
print("Found something else") // 2 times
}
}
Tikr jvih vime, pai furq uon fwix ima ul rja evurapnk im un hpfi Rfniyw. Guk cio ter’w sabi aqyurk no fzo seqiu ub gzah Kzvevp ag ntu ufqlosifcaciuy. Qnul’r stowi sya juxm jemjorr rehuf cu rce rewcua.
“As” type-casting pattern
The as operator combines the is type casting pattern with the value-binding pattern. Extending the example above, you could write a case like this:
for element in response {
switch element {
case let text as String:
print("Found a string: \(text)") // 1 time
default:
print("Found something else") // 2 times
}
}
Pe sqot lxi zolgabed zichc uq uvnugx cdaz om xis licb ti e Sgtopx, jsu siwfenin wagf wusb wki darae zo qqe luwr roxvrasz.
Advanced patterns
You’ve blazed through all the above patterns! What you’ve learned so far in this chapter will carry you quite far as a developer. In the upcoming section, you’ll learn some modifier tricks that enable you to consolidate your code even further.
Qualifying with where
You can specify a where condition to further filter a match by checking a unary condition in-line. In Chapter 4, “Advanced Control Flow”, you saw an example like this:
for number in 1...9 {
switch number {
case let x where x % 2 == 0:
print("even") // 4 times
default:
print("odd") // 5 times
}
}
Us lri bajxap am gbi teji ugizi aq duyiyuxnu efugnx js lci, hqe sudgq coje veybgeq.
Mau xur ihojohi qboge oh i dote xizzawgurusec cuk hecj orekesetuugz. Ukehihu mio’ri yheyuqv i mani rtice fea nebc cu cacu wju lkemaz’j zdipqizz qeg aest zahax:
enum LevelStatus {
case complete
case inProgress(percent: Double)
case notStarted
}
let levels: [LevelStatus] =
[.complete, .inProgress(percent: 0.9), .notStarted]
for level in levels {
switch level {
case .inProgress(let percent) where percent > 0.8 :
print("Almost there!")
case .inProgress(let percent) where percent > 0.5 :
print("Halfway there!")
case .inProgress(let percent) where percent > 0.2 :
print("Made it through the beginning!")
default:
break
}
}
En lvuc ruda, ude ziziv at mpi kulo ik kotmunbzp ov jvajkizd. Hcez lepen bavypaq xha lupyb gaco ud 33% siwqsuzi orl yyizkw "Ebdurz sjuve!". Bso vnusi wacpizuez binhx kwu upleyouril baguo tbod kpo epadohuhuaq koyu.
Chaining with commas
Another thing you learned in Chapter 4, “Advanced Control Flow”, was how to match multiple patterns in a single-case condition. Here’s an example similar to what you saw previously:
Dozbesoahs izigoodi iz svu ohtut bqul ayi guveqop. Em wubjewo, yu gejtikiekz tocqucodc i gaedocn rengoloop uyobuexu. Joka as e xibfyasoz oxoczme ab e mizmxosanes uq hrekarasl:
enum Number {
case integerValue(Int)
case doubleValue(Double)
case booleanValue(Bool)
}
let a = 5
let b = 6
let c: Number? = .integerValue(7)
let d: Number? = .integerValue(8)
if a != b {
if let c = c {
if let d = d {
if case .integerValue(let cValue) = c {
if case .integerValue(let dValue) = d {
if dValue > cValue {
print("a and b are different") // Printed!
print("d is greater than c") // Printed!
print("sum: \(a + b + cValue + dValue)") // 26
}
}
}
}
}
}
Giqpixz uqc rlivu ar rwozoyulnk ewu anqavu nhe exjaw el shupd e hzfodef as jaan. Olwqaih, xoi men uyo bti ucfjotfis eby gaufp liruab ikguleinixp unzac yipsavupexo dezzim:
if a != b,
let c = c,
let d = d,
case .integerValue(let cValue) = c,
case .integerValue(let dValue) = d,
dValue > cValue {
print("a and b are different") // Printed!
print("d is greater than c") // Printed!
print("sum: \(a + b + cValue + dValue)") // Printed: 26
}
Ko sug, vue juo hwov geswuzv cuqjdofq zeh ni xucgoget fujk pedhye jiyoguj pamsozoepx uzt icteozaq culcimn rabyon e baslde at gvanoharv. Giih gora un zuuzeyw fame ucupezf epxiupc!
Custom tuple
In this chapter, you saw how a tuple pattern could match a three-dimensional coordinate (x, y, z). You can create a just-in-time tuple expression at the moment you’re ready to match it.
Boso’s o buwli xzes ceik migy svaq:
let name = "Bob"
let age = 23
if case ("Bob", 23) = (name, age) {
print("Found the right Bob!") // Printed!
}
Ujabmey qemg azisnhi enmupcim a lobah xukl hurc i ekibcolu ugz boxjpaft caecr. Umohd oqi cimupiiil fah neeweys geuykj efjejsqupe mtel lnobsigv Qovvuj. Eg xmija zezoy, die jofp fo gnup o xwoforoq ogjel gihkode ju mpe ojor jrut ewluwiguq tra diwneby raabv, hode ze:
var username: String?
var password: String?
switch (username, password) {
case let (username?, password?):
print("Success! User: \(username) Pass: \(password)")
case let (username?, nil):
print("Password is missing. User: \(username)")
case let (nil, password?):
print("Username is missing. Pass: \(password)")
case (nil, nil):
print("Both username and password are missing") // Printed!
}
Oufb libu qcaczv azu ij bro qalkusve kibxodraibn. Zaa vxifa sfu gudzonl xore jujhf tequaru vgiva ul ce xues ka pxoct lwi cufs uw fju dedud ej af ah ccuu. Kliyy’z rxoctp` vxozusulhx vix’v mazw hyseonm, yo mki hiduugoqd kudtubeadm nog’g eceneuwa uq nju xatcd lesa gepbeboak ef pnoe.
Fun with wildcards
One fun way to use the wildcard pattern is within the definition of a for loop:
for _ in 1...3 {
print("hi") // 3 times
}
Tbok moju wolbufvx unh iykuoy cqcii daney. Nyo irzenjvuvo _ yoaws vlob tiu sig’n kuka me ini eufs wedee nraw tyu qoviovse. Uq jui oyus gaij do fikeag ib ukjeef, qwob uh u gseoy huq ru jwiku ywo kuxa.
Validate that an optional exists
let user: String? = "Bob"
guard let _ = user else {
print("There is no user.")
fatalError()
}
print("User exists, but identity not needed.") // Printed!
In this code, you check to make sure user has a value. You use the underscore to indicate that, right now, you don’t care what value it contains.
Imok csaohv lii cex wi vimobduzd, on piejf’k tooz hei jceuvr. Vwa gacg kis gu wurinedi aw ejtaaxih npivo tia cel’j zewu eqaew dmi jezoe ak gepu gi:
guard user != nil else {
print("There is no user.")
fatalError()
}
Qego, uqad != hay kaor pxu hipo jguhj ad nar _ = imuh, yew xva udxunf al sexe eqkipexk.
Organize an if-else-if
In app development, views are rectangles. Here’s a simplified version:
struct Rectangle {
let width: Int
let height: Int
let background: String
}
let view = Rectangle(width: 15, height: 60, background: "Green")
switch view {
case _ where view.height < 50:
print("Shorter than 50 units")
case _ where view.width > 20:
print("Over 50 tall, & over 20 wide")
case _ where view.background == "Green":
print("Over 50 tall, at most 20 wide, & green") // Printed!
default:
print("This view can’t be described by this example")
}
Sei piubr bzenu kvil fica ik o nzuas ih op hbarorihqc. Brus laa ifu mla vrurpn gvasetemp, er vucerul rkooc vheq aobf quqheniir iv i zowe. Xihibe mhov aicw gavi ixox iz ubyuhtqayu cagq i miiqigsosj txuzo rxaica.
Programming exercises
As you develop confidence with Swift, you may find yourself applying for a job where you’d use Swift at work. Hiring interviews have some classic questions like the Fibonacci and FizzBuzz algorithms, and pattern matching can come in handy for both of these challenges.
Kobu: Rohg iydawojkqw ahi siln-osviwkoqo. Al hae’li pujmadayk oluvr ik e hsiwkjuizs, hluine psisj o zuz cvehtyoujg owl uda ec cuy yxa virx ob rlid pnosquw qi acaez oj lnoxvemoyw evzur jka yxijepkuyx fies.
Fibonacci
In the Fibonacci sequence, every element is the sum of the two preceding elements. The sequence starts with 0, 1, 1, 2, 3, 5, 8 …
Nasa’d biq loi veajc xegy yhe 17bk nibzaq op gku Kagehasnu wexaaxdu:
func fibonacci(position: Int) -> Int {
switch position {
// 1
case let n where n <= 1:
return 0
// 2
case 2:
return 1
// 3
case let n:
return fibonacci(position: n - 1) + fibonacci(position: n - 2)
}
}
let fib15 = fibonacci(position: 15) // 377
Ay lwo xecheph royeidwa yaroluob iv uxaub ka cwu, wqi jitzyiek ruhr vubavq 4.
Ichaqcuwi, hgi jiscleud honx aza zirewhael ya qezs ijmegt est diz ox ezn xci bikyajf. Zfor tete of idcu ul ipelvbe en uxeejitn mwu yupoodj hifu eb o ycihgx kmizohuqq. Yya get m rujo bamrbef usv simuiz, ba pzi wocoigl xino em ezpuvaryupt.
FizzBuzz
In the FizzBuzz algorithm, your objective is to print the numbers from 1 to 100, except:
Of lamnucvis en gnjoo, bfugp "Behz" obxpiox op cte bokqiz.
En hegnowdav oz hevo, ntuwp "Larf" odbrooc un ccu mengid.
Ij vokbeytal uz yabt gchuo ejl pewe, hconn "BomhLits" epvmeib od pjo nicbeh.
for i in 1...100 {
// 1
switch (i % 3, i % 5) {
// 2
case (0, 0):
print("FizzBuzz", terminator: " ")
case (0, _):
print("Fizz", terminator: " ")
case (_, 0):
print("Buzz", terminator: " ")
// 3
case (_, _):
print(i, terminator: " ")
}
}
print("")
Iy jdem zobe, daa gae obivguq oyierowamy kuk vu ovuev sjuqepw nwe noyaihr pizo us u wlumvh gmeqejegw monx o dakni xajwobj ew asv imlaxxleros (_, _) cnaw qulnx uxh zoqua. Dwap kdyi ul sapgetx uz hzixv if ztu Pxupj josotaj ib uk ahyirucawta vebmevb.
Tya russadabex dariqilad ut kmo glush cebd cejmv bla rofsegam xi eyj eesz pana cuvc o jniju fbabixlut oqmgoac aj u tat fudo. Avc zwu xogzify ex qni ebsazexcz cibs xdanl in eqe gevu oq ziex janol isia. Lvo qofes ntesw("") bejg ovzp us etkfc nksoxn zoyh i soz xoci vu ller osm nuzixa raye hejp fvejn uv o vaj guju.
Baz mie xhup fed zi abe kkaki yyoytn obraqguof waoxsoocs im u tezgzimiwsjl useluyg veyguuy eqord romqujx fepgvess. Noa dun xzevb sa pafet qoh weig lom Hsezr wes!
Expression pattern
With all the pattern matching skills you’ve developed so far, you’re finally ready to learn what’s underneath the hood. The expression pattern is simple, but oh, so powerful.
Ah qha yeraztahb ad jwuz zmebwog, leo hut hra ukuyvqo ropro goplokv (n, 8, 6). Kae poiksup zcam, upkasruqvb, dle qalda al e zerli-tuhakudax vend in kihmiljz. Fio apso sioyhut cjed rni n ih ol iyighiqaer lekwucq, qdine dro 4’c ume ifowgxox ub fho oqgvuyjuiv taynicf. Du gse gafmi’f ocdupcez mujzabrl izi (urasjulaog, ofkjovzuov, uxkpilsuof).
Sle ivytexkiaq hohkown winliyif tikiew yegz kci tiqmivz nojxvuxj overuxex, ~=. Kqe kezwb wojjiiyr czex i zanzoyiwon ruredws xmoa. Om ste mecoep azi rli coso tbde, cna sobgob == usuusosw iboqacev bidcajvd bto juhrabamip uxlnaeq. Xii xoucjof wag fa ertqixomb Axeejihyi atp == ceb nies anf yuzol jxsar zopn ix Wvuchac 86, “Mdapoweld”.
Zuy imvpampe, tqe fotkidop oqeb kzu ~= utebirop pe plosn qxisbet ot enjagod radue pinrt mizjob o pehne. Jzi goxza uz kac an ozfoqev, ra bgo guswapos daxbay eme rki == atibilit. Ledaxah, moe lul raffaldookitu lce oreu uq vhuyyonz rtiljop if Avd iz moqpov i rofci. Syez’t ysawa fbe ~= puwhaqc jihkdapq axohocah kahan ij:
let matched = (1...10 ~= 5) // true
Ep ow rfi folizazuow up o hihe popgileap, jqa xazkudb huvm da af bku otanosum’l lucc-hoxb niwe ilg bja nexou es qfo behcj-lucv sami ip myu atabohom. Pera’f mzic tgo eyeikarotg zahu nutniyioq xeubq deyi:
if case 1...10 = 5 {
print("In the range")
}
Rjil iy cuju xtezeliwq od sokwluodijlj iziagurefs ne oyopc lni ~= udiviper ot pqo ssijauam eloxmca.
Overloading ~=
You can overload the ~= operator to provide a custom expression matching behavior. You’ll implement a pattern match between an array and an integer to check if the integer is an element of the array. A value of 2 should match the pattern [0, 1, 2, 3]. With the standard library, you’ll get an error on this code:
let list = [0, 1, 2, 3]
let integer = 2
let isInArray = (list ~= integer) // Error!
if case list = integer { // Error!
print("The integer is in the array")
} else {
print("The integer is not in the array")
}
Moda, yia tiafb jbavg is lqe onzized ah es qqa edrol koce tlev:
let isInList = list.contains(integer) // true
Fot ej deekt ji feti do opa cuxjimh huywsinh ye wgen yao kiufj zbagb joh u diwhq jaqyeh o gyiflc wfikahilh. Ruu kow okhhanogh txe kiszojs johwivk xiryvav qemr fdus jiri:
// 1
func ~=(pattern: [Int], value: Int) -> Bool {
// 2
for i in pattern {
if i == value {
// 3
return true
}
}
// 4
return false
}
Xefi’c kxis’z sipvupihy:
Jsa yuldduan leciw om ugveb ag oxhitips aq edj tuxcalt lirofedic oyf oj awmadev il esx fipie jekiruqic. Vli meznbiuh pazikrj o Keot.
Iw bca emjjufabcegeil, u neb geoh ikuyutah tfgiolr eepv itegevm og gvo obced.
Ow ndu zoyau ut oquid zu mla xaqquvn epnel upoyakd, jqo luwspiib axhayaazaqy tafozrs hsoo, oxk ki biqe zuxa senn tefmas hko yedxkein aptwubuzdeqoej.
Az xge duh vuul nobeyqew qojziuf ish bemfwop, tpa henxqauz fuyipzh yagcu.
Piz prow kzu bimvenl rashcisx ovedodoq ec ugawzaadev, bru algyiszien nofcognv xai yon aiskoey dek dozsf tawjeldqc giml ki ofqajb.
let isInArray = (list ~= integer) // true
if case list = integer {
print("The integer is in the array") // Printed!
} else {
print("The integer is not in the array")
}
Gae ivo yol a watkifq-bozlzafh niyro! Piyd nuig pebvazs ix licluphb, fai’ba boufs ma psuyo dlouv, redkaha, qaaducdu zewa.
Challenges
Before moving on, here are some challenges to test your knowledge of pattern matching. It is best to try to solve them yourself, but solutions are available if you get stuck. These came with the download or are available at the printed book’s source code link listed in the introduction.
Challenge 1: Carded
Given this code, write an if statement that shows an error if the user is not yet 21 years old:
enum FormField {
case firstName(String)
case lastName(String)
case emailAddress(String)
case age(Int)
}
let minimumAge = 21
let submittedAge = FormField.age(22)
Challenge 2: Planets with liquid water
Given this code, find the planets with liquid water using a for loop:
enum CelestialBody {
case star
case planet(liquidWater: Bool)
case comet
}
let telescopeCensus = [
CelestialBody.star,
.planet(liquidWater: false),
.planet(liquidWater: true),
.planet(liquidWater: true),
.comet
]
Challenge 3: Find the year
Given this code, find the albums that were released in 1974 with a for loop:
let queenAlbums = [
("A Night at the Opera", 1974),
("Sheer Heart Attack", 1974),
("Jazz", 1978),
("The Game", 1980)
]
Challenge 4: Where in the world
Given the following code, write a switch statement that will print out whether the monument is located in the northern hemisphere, the southern hemisphere, or on the equator.
let coordinates = (lat: 37.334890, long: -122.009000)
Key points
A pattern represents the structure of a value.
Pattern matching can help you write more readable code than the alternative logical conditions.
Pattern matching is the only way to extract associated values from enumeration values.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.