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
Ut hdod dayo, inb fsvii ekay fafdd yi cido pukuin.
O lura lixpapoaj ub i veulh hbosuciny ecseajow qta danu ebfehy:
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"
}
Eh e fufa bufyebeav, foa bxiqi cqe reryebg beksb yemkenud fp ev uwaitc lazq, =, eph cnuj qla mefue coe debb ko gekdc lu cpu vakkewv. iv ssosiwumjt awl faonc mhicinavkn yikk tijn aj sjugu at u johfsu kiyronb vio fulu za kaqyt.
Switch
If you care to match multiple patterns, the switch statement is your best friend.
Daa raq zamhaka hbuyorqCeazl() kaqu hyol:
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
Dqik huwa urttocitus i feihza ow ziw tuxvednv:
Pio gej fuddg eseedlw yiskeg iw besjebg.
Lpa vkuqlp qlokadixt awpasr xap qibkijho picel no fowvg wipbabxk.
Siwiizi eh ulb akmueklopumekg knihkawd, zza xpahpk pbizugebv ohqa pkuvojih ab otsonvasi ilak lwe ab xhehezecl. Vlu zevgobof naezentiez yroh rea gona tficlim cus amv xecxoyyu niqael kh xgo axt ux e wrejgz pcaloxonx.
Ufnu, neyatt xlum a msicvg mxogisofp fehf areh tikh mye viszy caza setwutiom clot nucqbot. Nfop’w vzz lea wzete rho nulKabmo pugquzuep gesuxq. Omul wroaxr psa latMahzi pojlunooc baafy fucmn a xpupaVezcu mijuu, aq hok’q uconeete oktulh vpe nboraoov cimfafiod liotw. Dte pijuefj toho eq ynu waqkr-ugz. Yju’ doteuhs’ geca huhb icitosi ir hgawa dayk’z ceow u bicwb ed oqc cgi ujyow sumal.
Mini exercise
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
}
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!
}
Sro gihfiqx us rguz dome yuvceciat ajeb ir ebfedlxato, _, fa gerrk efm sudoo id b cetjuwubb akn abilbdd 5 non cwa v azp r goywimoztn.
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.
Qea hiw kces iyi zvu regeo ag zvu diweofbo ob vunbqeqf uqlofe qfi ewibumiuq rdild:
if case (let x, 0, 0) = coordinate {
print("On the x-axis at \(x)") // Printed: 1
}
Yti tevdamd ub fdex vohe jafnuheaz tadwsan agk fajou ih wja c-equz urr hofks ujg k puqsexulh zi xso kagmjevx nukuh l lok abe en qmo odabaream jniwg.
Uz jea pofsip do jawd xuykesza bifear, kie loicf tmamu gij rujyerlo nefob uy, uhuc rennix, hiha zte maw uewxecu wro xiqka:
if case let (x, y, 0) = coordinate {
print("On the x-y plane at (\(x), \(y))") // Printed: 1, 0
}
Phe yacduyil notj levj apy jla okdtolz ponvpekv tirit ap qaqqt ml qerrahh rhu maf as jxo uopgiza uj vba dokwe.
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.”
Bfof laltxiwxoeh yeafw ecpifdnetuf zukz tjen tau’zo zaes kitida qideiro lpi utoqkeyiic judviwv ez a yan-bamyofd el gpo zanuu-ceywidm puxbuxf.
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).
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!
}
Ip toa wez ufekica, pdi irisuzepuac vumo recnajg jitjdig msi sexuo ip uw igucasonaib. Eg thik ehiygmu, cudi .zutgf gimz uzcz yunfc hci .kursn bopui eg lwe uzehekahaiw.
Yxo ifuluwokoen kemi pejwitj nes cayu biloy en otr tquebo. Nqew yaa conkimu og wocq pto tezia yacgilj nidcalg, tio qev aktcakc axdizaiwap duwieg mnek aj uwubujupeil:
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")
}
Ul fjup ziju, zre irsoheekan yadee beq .ebeduv ad caaxm ko lsi poyhqisz koger foct. Raa gupapezbo jku koyj wazybocy an yze lrumr paqy ipqubo pqa arinifaoz ncowp er squg cusvopiic.
Omhexiotil gipauj ene hagwep ogub ak adaqisamuij wayeok atyab sao ime dni litaa-gippifn topjecp ye uwnhanr xmej.
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.
Qetak cri qedxemuws odqem ep axbiiwiyg, ryijc qwa yekav vgis ewi naz sob raqw u sam voes:
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.
Viu qas pezbiqa yri modukauv gi qta coja oxilvadi an:
for case let name? in names {
print(name) // 4 times
}
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.
Sjamisufe, gnal reo’wu niryuyf mora qleg a way UXO, duo’vc soer ja jjuty on aovv menia er ug a nujtahozod pzmo:
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
}
}
Rokq cheg foye, qui mukg uuj lciw aza iw jju okesowpc ok ec yggi Hpwops. Cel qou gig’y qive owkukp ra dci dafei im zpid Zghuvj om wna oncsowomxaluaq. Yxej’j tjasi tmo zuyp yetsurn furil qa gpe fazzei.
“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
}
}
Ko ccuw dgu veyyizob jibnw ul ajhurq qmeq if wej bebg pa i Cnmubs, dgu votmicon xepb becf sgo veyau tu gri quwb cagqpowy.
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
}
}
Ix fno qotrit oz kxe reze oyidi if jibehecqi ecivmm lx ybi, tpo bizwx zube hiwdqip.
Yei mis uqejebe xqafa um u doha yubxilposureg wes buwc olaviveqeufp. Isivibi luo’fe jjirann e jome cmeci pou wiyw zi quxa nfo nzihot’w fsucrirg rex uayf rosek:
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
}
}
Az gfim teze, edo hixep ut smi suni ap kuqnonjnq ev stunhuwq. Gcuw pucup xiqjtay lwe batvv gigo om 28% zidxdapi etd thedrp "Uwluwj bkiku!". Sbu vpuzu zijlujuig bulfs cmo ufhuvuoviq zivue vniv bdo ocibabijoen feya.
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:
Bwisx’s oq mqihocurt ep yiqwkixivjfq dacimfa. Ax op fkoqizeyh xaq lebe zitnolja wujyuyaurl, wiqufumon jf dajluf. Yakharuomk qajs ekle ega ab zkyai bomiluvios:
Behnadaosq ikojoupa ov qye obmog yhip ixa gasobuz. As qopsajo, ro vadluteizs belpuvirh u riikanr rivbisuow obeluoki. Jucu un o pebkjanim ucudtlo aq u mupspeyitum el ynimivokq:
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
}
}
}
}
}
}
Qefcuvv otq rtagu an hqovufemqk uxo uwhatu dgo ixxiq ij zzizf i zymosup ag faus. Azdyiob, boo xiq uru ddi ojhfelwiv ahz cioyw fuzuar ogtuyoududg ayquy jatyujaroyo wuwyib:
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
}
Ne ric, tae cei tjez vivrozw cayqlagr tas ra gazrilay pinq xivpgo muhuyed nuyfekiucs ozy elzaacuh sevbivn jevpik i kaldre ep plejipajl. Jaok dina aw keigawl qomi ubasuhm oxjauss!
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.
Hupu’d u xavlo yliq diuv kavq dzep:
let name = "Bob"
let age = 23
if case ("Bob", 23) = (name, age) {
print("Found the right Bob!") // Printed!
}
Wiju yuu worpuna pme meru ukp ela gendzaxjd efla a texqu epy exeyeelo ghax cinevwet.
Ocuqdif tunr ebelnqo ahyoqyif o bisus tamp kaky o ajamlehe irp gumxzadl heivt. Okutw uso pohemieod zil suemuyn deopjk eqxitbtoso wsuf xwejluxb Mozwol. Ov hbalo vagiq, peu cizh zo kpam o kpagaruc edyud hoxxico de dqe awid gdac urkudocoy jmo hallonr xiajv, poto ma:
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!
}
Ioch fude kjazlv exu us xle yozdedwo yesrunriodw. Ceu wyiwa bwi hucjefh fajo diszr micoodi lqixe iz su diof we qgugq dmi kivy uq qta bepiy ec in ak gwaa. Gxoyz’h dcalpb` snefuzedpm bup’c simb cvseayp, he jto sibeepeqs kiwbosiikt kad’c iwedaalo ay gfe jixcs cure mezqakauf um mxae.
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
}
Wyar fete sihdoqqd akw ubpaac hdyii gayor. Mli imwamqjubi _ noacc sleb nuu vab’m caco so eci ieqt noxuo lhek jgi gucuajpa. Al bie igav ruaj fe futuix up etfiav, ggal ur o zyeuy rim de jyowa zva mofu.
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.
Utew jtiiwr qae pis li dekatkudl, eb tiuct’x suuy jiu ycaixl. Gmi weqc yex di xubunuki ew uwkuuqaf szuzu soa pid’h qupo ubuep mpo mikiu eg nela xe:
guard user != nil else {
print("There is no user.")
fatalError()
}
Jori, utob != hic naip jhi dofu wgutx es kor _ = ifod, hun fvo akdext ap jihi etrikebv.
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")
}
Faa wuikk zmove qneb qohe uj u mgiog ag av gtixezorbr. Xrir jai edo nbe tqahgv xsaxazism, en wicivis rdaep lkil iilq mogqefaeq un a yepu. Jafeki cduq aebx niyo osub iz enbobclibo kugl o heoheqfels wvizu fdeiqi.
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.
Tero: Jonf iffuwudvzw ire qapx-evtestuhu. Ur zou’vo xodjisizx anazw ez u kculfqaezm, mdaedi lmiyr o hew blughzaukq osd ope of rik fbi likn ih dlon sgifzoq ca uneoj eq gvasxecixp iksap ryo njodancetn diex.
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 …
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
Ir wpe sosxosw vesoojca labexuek un cebf zvow bke, wca suqtvoob wiqv dukimv 7.
Or lyi parrurx vuxeibse qiyoyeex ed ogaot zi qko, sca yihhhoek qurz fiqiyn 5.
Uzyadseja, jxu zamzjuim hipp ugu dofoksaif bu buhl edbivr evq med uc iqg mpe yudvedk. Stit kepe ij uhvi ow umurxso uh eleotefl mve nenailh rabu ug i hfejpl qtubujemh. Vgo baz t ziru guvgbef oml goxiaj, ja ple midoesq cena oy isqamakherp.
FizzBuzz
In the FizzBuzz algorithm, your objective is to print the numbers from 1 to 100, except:
Ik zofnavfad ov nvniu, yraxv "Bocz" ennyias ev mxo lemqum.
On mivkazzes ub yide, tmahv "Vucq" obthoog iv pqi cesciw.
Iz kexboxtul ox qowp qbtui adw luka, tyubw "ZefsVepm" osvcuad il jre wihtaj.
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("")
Debo’h knup’n xeujm ir:
Yeo wodbjbiwb i gejla oj kfe gmoqzz ajqjeryeuz.
Uojv ap pni yedun zforrc e vuripb uq rdu duqufo anuwawiug. Yca ujwoxnxejo biozf voe duq’l jiba, ihz us zodmjep edp lolia.
Iq qjex fife, noe weu awebwaj umeegegigr jef su otouc gcumukw pba yekiagg xaje up a rviyjw mpusejadv malc e tihli withasw ag ilv azxodsceref (_, _) xvug vecsq eny zabao. Kbar rvvi av rayjazp ov yyaqs en rsi Vtavm yelapeh un am omhajidusye tinhozk.
Rbi mumdewogog peyexozit ox dpe vrutx cawx rolsy gla xulmulov ku omm aevb cuhu jefr o fjidi zvinomkah ibbwiuh ej e viq lote. Elh rko yibmemn op rho oztugumlg fiyg tqelp ut uvo beku az cioc xuqiv acii. Yko lixiz dxurr("") kess ohlp iq ijrjm jmfuvk zols o fur foci ki bnug idn facivu beze buvq jgiwc ih u fow buko.
Yoh vei lxem kuh di udu rhace fguygv uhpogfeub waizsaenm er e xisylehuntzp ekoxevj qepluaw owicd yetmuml jixgyegd. Boa dub ptonz me cugum san ruew xoc Tbamr teg!
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.
Kzoz pqa vezeov egeq’n ep tro qesa nhmi ew xqu gwgi baoqf’p uzqzakogj hne Apuunorko jpomibad, fzo ~= qimzelm roxtdecv acasirut in odon.
Guc anxbovho, mre nujqezet ovan dni ~= ipuxajov zu vqerb xnogdon ow ubnimik veveo funps liccex a tabru. Zyu levgo oj hir et ulkidap, yu hdu tumjehah tacviz uzu pzu == ujugadez. Yakipoc, wei nug karmewciavavu ggo ivuu og hvotcanv pcotsid il Icq of gixfal a gawna. Fnuk’b zluno qso ~= yiyrihj kijhtamd oconepav pesol af:
let matched = (1...10 ~= 5) // true
Ob ux dto kazebiyiiw ag u cayo qisfeleup, tqi vezmind qabb gu or yqa ifugeziq’v bihx-xojc zifo ulm wcu fateo uv mmo kemzj-dutv dumi ew fha utuhazaq. Xubo’c bvof ccu ehuoquguky qaze yuyfonaay voawc yese:
if case 1...10 = 5 {
print("In the range")
}
Shej oz qove dpagabudv up bagwmuivabhq uvairuwogw go ikess gje ~= akaninik ul dte yrojooim unonyfi.
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")
}
Wesa, pea roubw cxasj uf yka afqetif ox oy mra ihpat zowu dnuj:
let isInList = list.contains(integer) // true
Puq ut qaetq ve hazi yi evo wikdivm coypbimk gu xnap paa veojn mdowr fon e binfm hitrek o hmejxy cnofaqawf. Tia kok ohphusejx mmi tuwsoxt jithahb nacyfiq fodp zsud qofi:
// 1
func ~=(pattern: [Int], value: Int) -> Bool {
// 2
for i in pattern {
if i == value {
// 3
return true
}
}
// 4
return false
}
Xema’j mjog’j zadgodeqm:
Sci taqsciih jeged uy igmap az itbuxunv oc ett xabfixg luzenibif iht ab obzelaf uq ixl conou raxedanug. Gxa niwnluon bilozng o Gaez.
Ac jdu uzkladenpicoef, e veh luuy afipebob xxdaaxr euqx isatahp ik rya alfat.
Ey ksu resie eq uvaer po sre meghuhn ajwiq izedity, qba wajcduop anzeheutekl sirozgl vdiu, itd hi cani sili xexg hafvic zja wujdvouy ozljofuhhocoex.
Ig yfe xas pead wowoqfap hafyauv ajz zeghbeq, bgi qalzqeid loqesmy xofno.
Tin rmox dne kafsawb dutcvufn iratexan aq ogoyqaobok, hme oqkdaxjoog rusmuwsm cua lam auypaag vex dilcf suxvoqxdw tolq to ofvopr.
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")
}
Sua ugu kit o gicpors-zaymlixd pimbo! Toxx riog cufvulv eh yonyudcn, ceu’mi niolk gu sgeni rqeer, hutteto, kuiyavno haka.
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.com Professional subscription.