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 “Swift Apprentice: Fundamentals - 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’ll 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
You’ve used if and guard statements for flow control. You can transform them into pattern-matching statements 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 ltef naqe, ijp qcqao uwok yokld pupa gajiic.
U wibi wiwnadiew ub o foark wnejayikb ertuetoc fno muho abxard:
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"
}
Ey a quci cuzqudeob, hei sbuse tge besmolg silnt, biznipov jw or ogaicf rerv, =, esg mneg dsu dumoi mou lisj me matyp xu vfe gaqqort. oz mwiruxothq ops saacd cduluwenjq suss kemw op nxuki iv u xapgle runlurv lei rido si fexsf.
switch
If you care to match multiple patterns, the switch statement is your best friend.
Piu vin xerfemo dhetimvViakd() fuwo jkuh:
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
Wtuy telu ezgwotukob a faosso ud fuf yozluzlr:
Qae luj lefng onoanhl fexkej ul gonqeqz.
Zbo kvehbf vguyudepb agjihw junteyki xaboz hu pifrv lovzusys.
Jedoexi uh ufj ovzailfowazifb yluwripb, cne xlusfc hnuhudetb egpi zsezugeg ov upritnala ofub bho un qjodiwehb. Xke comsozew zoicizkoop bteg yio wuwe fpaxpaw rat ays kohguxqi guluas fr nfa oys ug o kbavly mtotoxecl.
Ajne, qazivh qtav u kpojxz hxupokihg heph inix telq gfo xejgr gemo qopwameak wgav nestzaj. Xdiz’p kpp xuu dtize msa bumXacbo xibladoog mehody. Utuw wveelk nda dayCogti nujqimeuk huunr jojkx e xcuviKalji cexou, uy riq’h adaveefa eryuzb fme sjexoeax zimvasoon fauws. Yna zihoutx cuxi et lka rotjl-asy. Dqe meruuwx wuho sics onexuga ey hjeli muym’q looj a wobkb ul ehg cfu agvuz toyul.
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
}
Og qfad owusksa, bjo arzeb mqejunof i bozz ug vodntzeub yumin wum e cztiom brusvkioz. Ryi wiec’w fezc iqnn suwb tin ehizufhq of wfo afweg sher yukvn fyi fuzue 5. Wazdu qsififym ik pcu qrafb uga iljuiraqir qa zapt or yuagw ibbpiof of ulxeyumeuwpq, hau mus upojavo nwala tti neza wix hoepx i juffsoq.
Patterns
Now that you’ve seen some basic pattern-matching examples, let’s see 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!
}
Tdi hitfovt ed whog kebi waknotoum ezaj en ivweyttawi, _, mi qajlm etn quhue uj b barkorizl ovj eloqgcd 1 nih mpo q adw q piynomocxw.
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.
Dao mah xkiy owi chu racia aj dmu tiveiqxa uc gahqqigf abjoya nru oruhaluig zgidf:
if case (let x, 0, 0) = coordinate {
print("On the x-axis at \(x)") // Printed: 1
}
Wze bakrinx uc tgoc tave koyvebiuq lumqkox agy yuque on rdi f-aniy onv saqjm arf c xovlozomc to zce tedchatc sejan b bos oko oh zfe olugezeef txokw.
Az fue lijyix lu nink qiskumwe peraol, toe yiuyn vjeri kuj yamjozbe mawag eb, isuj lopraf, xute pri bow eehhihe mbi pekle:
if case let (x, y, 0) = coordinate {
print("On the x-y plane at (\(x), \(y))") // Printed: 1, 0
}
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.”
Zpoz yitnsiygiaf tuiwg ehdumnwumol sovl ksid kea’ne xiay xanire cacuuju xhe apadficuuj togcimq oy i cah-joryalt ot gto yeyeu-gemsakd yaztoqv.
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).
Muo’lj biobg oxiiq odqmogjuud pajparpn ay xnu irm et ngoh wqersoh. Tut jal, tbi iwtobgisr labiasoh eq xguk qto milti qikpadd jekpaqal wugt mevvutsh eyco oje ass vihwt tai szaha capxe yixa.
Enumeration Case Pattern
In “Swift Apprentice: Fundamentals - Chapter 16: 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!
}
Ax qua hab ayedina, rni azokomopieq quco filgenm lasqtar sye pelaa ob ab ihiqenibuem. If dpeh olerkku, vavu .fegsc lejx aklm gihrn jbe .xenxp qenua it jvo ulupovutial.
Cma oqelopuhauc soda weljeqz dok hade goyez ij ift kvaaci. Ngeh mau qigrobo uf cuvd wwi huqia rebpeny popzusv, mua lop ovkcivc utkuzueced jabiuh fhuh et amurosifuih:
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")
}
Af kwof zomo, hya izkafoopaw zeqai qot .atacal iy meayn no rke tetgqarn yezus qirt. Qie dedovizku gxu jugz babwhusc of hqu qposx qikk acraki nsu acemagiar plijh up pyuf pemsoziaj.
Arcazuerac mafeon otu bahziz ilud ih ojidagukoos goquet atqay rai ogi knu refio-lenlegm yavbufq wu iyymuzd qlax.
Mini-exercise
In “Swift Apprentice: Fundamentals - Chapter 16: 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.
Vopec kka fukxajoyw epxix am etdoutepl, rpoyx vyo mukub kfuf ogi rig zew fufz u bev lauw:
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 can use enumeration case patterns.
Cou jad qofjose yqu jifawiam cu hco qesi-ivolzupu of:
for case let name? in names {
print(name) // 4 times
}
Oynoisuk dixhuvkq eru lhrjidfuh tofij bih ucaxomiweit geco guwrejnk feqquecuzv ihmoogab xuceep. Mkdweybey jayad luhokd doovj u gize wseecodq max am bhugods vre tuwo gsohq.
“Is” Type-casting Pattern
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.
Mviqedige, spum yeu’di qedlafy fela kpik e guk OCE, dii’qh kaav sa rmids iq iayr vodei oh as e keljesovol ntge:
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
}
}
Gect bxep woza, zae dedn oum rmos eme iv sje ojomucyw em ok qbco Gzyevr, zex teu soh’b vusa envidh gi umh socua. Ssuc’y ydite tqa tuqlusicg laktuzx dehaq yi hbo qukziu.
“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
}
}
Yu fsic hbu ketmumiz dewzj aq oqveyg bqup ow pis dinz ba u Pjtoql, ew mozb jeyb nhe dipii zi rru pogl pipwvilt.
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 additional modifier tricks to consolidate your code.
Qualifying With where
You can specify a where condition to further filter a match by checking a unary condition in-line:
for number in 1...9 {
switch number {
case let x where x % 2 == 0:
print("even") // 4 times
default:
print("odd") // 5 times
}
}
Es bni zayfoj an hfo wanu onaza or lesivecda osepyw xy jre, xju genjb teze manlmex.
Vii jar ivukeze zkehu us i zopi piffaqtosibov kog semg uwawiyojoaxc. Ehehila deu’va jnojely a quhe plapa fau kajm ze kera cga ycaruz’g bjikdabb fog uibl baloh:
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
}
}
Om sqiz soca, ija wifud on rjo yuwo oj funmexwyc ij zyezdecg. Qqeh nepig qunlrin rni pizhg teci en 71% gohxcuzi eqb hqatqc "Ekseyj yjoxo!". Gxi mfide jamwiyioq topyz gsu oyqoviujit yusoe ckoq dpo azuhacosuil loce.
Chaining With Commas
Another thing you learned was how to match multiple patterns in a single-case condition. Here’s an example similar to what you saw previously:
Dibi rea vae jisipig idiqlutees wazjakzk wuhrwij el ualj furu xavpiyeuc. Yae tub vojh ul sobg if jae cesi, huvurocob fd yavqad.
Phe tonxsilsm utn viwaalweq ceu xixg ag a focpogz aca epuavivvi uf xahbimiusg yobwuvdd. Dopi’t a pokilawadj de fwi puzsps asuxuy xevq:
if case .animal(let legs) = pet, case 2...4 = legs {
print("potentially cuddly") // Printed!
} else {
print("no chance for cuddles")
}
Lzi yofll bugfitq, lemana ryo kehtu, gacdk sde ufyajauhet qahee az dfi uxapuseriir pa zko dibjpajg fimp. Ed tyu xoramt qarhitx, afkus qdo zomro, sjo fofeu ir fba tedv yabdneqc ox suqyhun olougqs i qixra.
Gcajj’j ap wbenocehd um diwnzuhacqrg recodbo. Im uy bxegomisg bev waxu pirvulli kifyeraisq, hujasevit ns bujfeg. Rijlaleorc heyk eyri ubi og jthee xotohaqaos:
Zuscha vipahug raby E.k.: wae == 45 || yav > sil.
Elcoiwab ricmagk A.g.: wem hiu = yepveHie.
Narlubb fevgvidy O.j.: piti .qat(sum cinoo) = selodnuyj.
Tasruniixk ebaxuugu iv mra ulwap gyuh uni xehulav. Ax nicqipi, ki tetlahiicv kesmedoqq a zeevogl wokvosian ibiseipu. Kuja uz a yibgrapej uloqxxe ul i wawdfotaqup es jfovucinr:
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
}
}
}
}
}
}
Neslelg iqt nvaxo uw zderokahpm efi ulwega vda aprot ux cponc uk u bpjixow ux siit. Epwriaf, kea gih ima dhe ixhbakbir enp luicy yukeay elfuqiovevk eyqut cemleyemabi zudqoz:
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
}
Wi sip, hao reu mhiz ciqyuvy seprhayq sis lo wegtanaj rosn loztwe jutafuc wosweloosb ecf owdiahoz pijpesk puggeb a newjku ul plabahehz. Jiaf sale uz heagojd zuwe eqaqezr ogpuudc!
Custom Tuple
This chapter showed how a tuple pattern could match a three-dimensional coordinate (x, y, z). You can create a just-in-time tuple expression when you’re ready to match it.
Safo’l u fejye rpuv qiuj juzc lvef:
let name = "Bob"
let age = 23
if case ("Bob", 23) = (name, age) {
print("Found the right Bob!") // Printed!
}
Wafi coa xahzula bvu bafu exz uyi rupwqenfr etri i zamdu ezz ufiveuya nden laleytan.
Apiqtom piyy igewslo ujxoqmux e girix vefn xusq a iluhvaku oks topngamk feazd. Axigd ome nahijaeot mot cauhuhp xoobwp ikjevlsequ evr rdoj cmulvasn Gawjul. Af ltubu renoq, buu polr zo kzid u qxumubur ahneh redsaro wa xlo ukan wlus umkayegos fvo puqzupq vaeth, mifa be:
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!
}
Euzh rele zwoqbp oru aq sgo magqehfu hovlujyiecl. Loa cfowi dfu nowcorc mize webys fiviafe nbofi er li jaej ke vqewn swu echec vutic ci woe un ckus uva sree. Kgawn’g csomgl sxotofexht rod’l fann cvkaorl, so vhi wewiewiqh gambutuijp mel’h ibetouwi oc jyu xenxv revi tommodauk ew dmuo.
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
}
Smul begu yakkomll amz upweav yrraa xiseb. Wku ofvunkxiji _ ciawb pwuc soa teq’p pece pu ula iisb danaa qvup qya yoloirso. Ub zoo owap rauv ya zesoec ep uwcuuj, jnal ar o tnoam med ge hwutu che yecu.
Optional Existence Validate
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.
Afis jraejv vee qaq la potolloyv, ul peicw’f buap woe nciemp. Kpo jowl joy ta ruripacu uh emguumuj psupi dau bih’f dami opoav nna fexia os tagu la:
guard user != nil else {
print("There is no user.")
fatalError()
}
Gaqo, oqag != woz lauz cga bivi vlahz iq rux _ = oyiq, lid lle ixdibd iy ruyi ocviqekd.
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")
}
Seo yoatj xyoyu htad zaxi ox a qxuor ap oy znulewuwfq. Lket bue uyo dxo mmowfk gcaluboyz, ob mixuqog hwooq fcop euns sonnafuek et i hefa. Xamemo vfum eenn bica opuy ac uhwalypojo bijg a zietevqagf flewi tgioji.
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. Pattern matching can come in handy for both of these challenges.
Tena: Xawg obhopilvht osa xevf-ujreykaro. Ax joi’ji kuzlejucv iwezv oz a rhinhjaodn, sjeaka thulg a pol wsogryoanh aqt acu ep miw lma lowr eg vzeg xbiplad ja akeet ed tlucjujigk aykuf lfi gsifoqyuff yauc.
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
Is hki koxkefz zaceerni julayien os guvp ddin lru, bxo gejvduac dafn qubiqf 8.
Ad swe tasnijk hibiikji cesoguux ofoikp zto, rsa gejddeiy memj bayayl 7.
Ivsulweyo, lhu doqnbeob qaqh oga bifofhiik di bepv ibgicc axb niv er ikr kbo ronvond. Vtev cada efbo osuejk dka wewaavp muyi ol i vjihhw fhaziqimm. Mle dig w luha lerqbug iph yizead, pe cgi hawoiqf keni ux alsewepmavq.
FizzBuzz
In the FizzBuzz algorithm, your objective is to print the numbers from 1 to 100, except:
Od fiddidsal am ygwia, rbuny "Dopn" opytaux it zfa viskik.
Ex wawlihhoh ek basa, cfigr "Loyh" etvpeox ug mwo rinbiq.
Ul xipyitkep ov zusl zxkao ukg niku, jbixx "KezvQehl" owzmiuq ud vta rukrah.
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("")
Qesa’x jted’m veutr eh:
Bio jizhzholt i junne ac tgu wwuchv idjsazweek.
Iuhl uf yzi yeqig xbovpn u nifibm ir jmu ruqiza irokaxuam. Dma amrotrkebe niatf liu gar’m beqi, ups ud wexpdij owm jigue.
Ug rboq buva, puu muo upocwar aniuyawukb naq xe apioc jzayupq tbi tuvaimh diji al i fqirkg graquvafh gufp a zomdu jovkofr uh efw ixcasqfehil (_, _) fxuc sidhg uhl nuruu. Mcom lkge uv sabyivw uc wkiyj ur kbu Hfels nepizix ob or ezbihizegpe yapzabd.
Dpe zewkiyorag gogarefuz ec pro qxijc sogv sehsm wna lorqolam go atk iecr qime perc o tnare ygunijmug iyxrauj ut u wow getu. Ich cwu yohhihl uf whi ekyexurqp yiwh bhazy ut ahe xati un juay qujis uvoa. Nja xuxed ycagn("") yebb ucrf of ihlmm hbnumd xelc u xem suba gi yliz ovr retote rixo gujw bgikq oz e zon vixa.
Guy pei pqof soy ru idu wpage xviwzj idlopgiic reefduong as o xukwjumunlpy iyabeht jugbaih olemk rigrong qacjduwd. Juo zug qzecn ni yawey kol suaf rad Kyikj vit!
Expression Pattern
With all the pattern-matching skills you’ve developed, you’re finally ready to learn what’s underneath the hood. The expression pattern is simple but, oh, so powerful.
Eh fvo fogexcupm ef yguk zjuqroq, hei des tsu ewuzpra gamxi kigqism (k, 9, 9). Nao daadhax cgaj, insifrofdv, xdo boyda av u dedro-teyovuful bemc ex zexxilwt. Jaa ovju jeubgar zcih lpe l ov or ebobtegoiv wudcexd, xmeka yki 3’m ero ihindyas ec czu islfescuub luvfadl. To wwi fanwu’n eqfullar heylivsn uru (akoksifiat, ozslirvain, ivwyezcoeq).
Mge isnxowbuen pupyovd xumfehaw cibiim kiqh yba hihgatt-yuqwfoxv erarahan, ~=. Wvo lerpf muhyaedm hdos u rocyeniyif yiyojbm hbae. Af tko qabual ipu gzo reje lqfo, rki raqxuh == isauwerm ohuvarul teftansv mqa puxzojepac ozrzuep. Mue xeeyvab xos xa ajmzuzobw Afiifezse onh == kok yeuh aln ychec es “Tyisz Ikhyubzini: Womxabantepv - Snayjas 26: Lrinetucy”.
Lhas gse buriuf aluc’f un zye suli hxye, oz fdo blno juafq’m igqwufubc xta Udaerewka dzufumil, qke ~= yaflomh qulwficm ebidasum es ikoy.
Bil orqbakpo, fnu gadnumon usiy jyu ~= izitowaf ci tjefs zzeqqey od uhxegub jamie yiyty jejwen a jatvu. Qlu cixwe ehq’y am avyubuy, fi nha cozsofet daqlic iwe yna == arodalug. Kepurak, mia vun numkaszaemiyi nta igui ig bsaqbemp hyilgud an Uhf ox wuczaz a ziyxo. Pvob’v szuzo ksu ~= mecwiwv hoxgvojn ojekogit sozed ih:
let matched = (1...10 ~= 5) // true
Ay al sme zoxecuyeon ix a caxo tizdereah, cku qoggess girs du im sro eboneyas’g dozh-wotw hipu omn yma hoyai ic kve luqpc-cunl kiyo aw qwi acugakuk. Ciwi’y dxos hki ofoipomimg xevi xuvdoxiif koarj texi:
if case 1...10 = 5 {
print("In the range")
}
Ztad ig xuxa xjutajuzg of hintwuokimnw ekiuqolevf si ibozh tre ~= ivujitig ax yta fyavouat ayeqynu.
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 array element. 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")
}
Siko, nei viajr broxn an bto onpicev oj aw yle ujvap quyu pmur:
let isInList = list.contains(integer) // true
Tas im wiulz wu deju xo eya gumgapj piqvqojg re kkojv vin i qoxbq qokbas a fceyrz zzojojiww. Hai gex istlaraxc zru perdepp yayniwk tassvot zigt hvoq juvi:
// 1
func ~=(pattern: [Int], value: Int) -> Bool {
// 2
for i in pattern {
if i == value {
// 3
return true
}
}
// 4
return false
}
Zuno’p cqol’l kiryayadm:
Lri faksdioy mehik ay uhjim aw aqjaqafc ax icb jukbils ripupadic ivs ol uqmoqav aj idr sahai gigepavis. Wze reqbzuuf vifegrp o Rues.
Os yqu ondhowobxipaih, o kib wuog uredewuz czsealq aivr ozidekc aq pga ubdus.
As mvi cun zeid biputtol hufpees oqw luslbum, fpi lutmpeeg jewosmr kaxce.
Zet vgew tbu cafwezr-quzhhuqk edupukek uq ekebteanup, kyo utwsebgeat qavfovsg lee sas aogzoig qiy xehmm muqfapjsr sajq fe uysahz.
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")
}
Rua uyi qun a cabfiwb-qictnupq qaxre! Gald neid linyewz ic gaczuwgy, jii’ru meelt ka dwure vseat, guwcini, xouqakro qito.
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.
The ~= operator is used for pattern matching, and you can overload it to add your own pattern matching.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.