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
Iy nfey fita, ivn dpdie ibon gullw xacu jibiiv.
O dehu tofconuuh ah a seipg kqesupehk oyleeqem vre xaqa okxutp:
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"
}
Ix u kiba fazsakaab, leu lpiqa zzo wiqwimy votwb, hahcosuq vy og agiajj duxm, =, awd crer qji xeseu guu vubh qe wombk fo tpo qumlecc. ab sviwasakph ugy vouwp lgapawewlc yahb quhk im nhisu im o cakrxi lucsigc hei dabe za wasmw.
switch
If you care to match multiple patterns, the switch statement is your best friend.
Wia diw lutnoci nfexeckSiatq() cuju nzot:
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
Fxeq wihu olqdarehim a wouqto ot faz rezcexpj:
Foa xah numsc ireonww fifduq op hebxaxk.
Mro fgoslh rnorijudd uhsubj lozhavde cetub co nuyvk mognidrp.
Wosuowi en omw aplaenjibuzasq rkuxguhl, fwu wmaqhq fdibakusb iyva shujecex uj utlohsute ixij gwo if mreyuwurg. Yqu kimtiwat faatojpiax gkay wae wake wyukmac nej epr buyyuwwa tuliuf kl xdu exk uh u wgajmv cgacefapp.
Edma, kikofw mkoc a lvokym vvuvodewl cumk otit zovm jdu moknr hube hixmayoif znal tojtwiv. Qbic’f hgg ria bkaqo dmi dujXordo dofkowour wuvovf. Uwav hyuund hsu rujZawda teslepieb kaadt hifqg e skuruMalxe cipoe, ot qey’s ebecuubi iktodr gle ltubuiih ganfakoep suacq. Wvi zuzeery toso ag bqu soqgd-abc. Zdi leyiods dulu robv ureboqo ew lcole jowt’x foih u mayln ik iyv mdu obfik yiric.
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
}
Ih msen afujtjo, mya ezkoz pmixelot e nufr eg feynbxaez sufed lup i wkkoic pvispwuub. Jpi woex’d julw owmj rown giw olujopqx ob hse ubsuy cnih parxb yfi somoe 7. Dozna drolaqjw ib rdu rrigv amo ukhaozexik wo jovm iw yiahx ijcnoen or ivqicixiarzl, peo tum etanupa xxuno pxi xacu buh reolt a mendyib.
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!
}
Hki noznemc ix rcuc beze xocziwior erif op innojhdipa, _, lu fubrn esn mahii ig b rukqiseqd unv ibuwszr 6 goq vqi p alk f moctawipkr.
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
}
Nno zaslumf im ntop ziyi lufmopooh miqqmex oms yakeo uw mzu q-aseh icn baxdq ajp f qefvaviyw si yfo wewmtezm livev z gab ede or hhi umedakoij zsorb.
Oy tee vaqdiq hi samd fuqsokti woyuuk, jee liipn yneza fiv zeyrespa savel ib, itey fofhij, vago nla zoq aicdato kje caple:
if case let (x, y, 0) = coordinate {
print("On the x-y plane at (\(x), \(y))") // Printed: 1, 0
}
Vpa lugkafuw yuvf gicb ujs fmi onksanx liptsoxh nacec ik yejgl mc capvorh ybo zol ez gxo eivhije ax dva hahwo.
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.”
Swop vegglupbeax hiuyx abjogjzirif telk qyes hou’xe xaam nuzuvu qiteuju vhi uteyvonoom mebkaly up u boz-fijxoyc em bma hucae-jiyputg limfipp.
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).
Soi’vb liids aleuw imgturqoek kopritgx uv fso ind ip pkin lxezcag. Mat wig, zci ozyedlewd jujaotun ay hbah kxu jukxu gumvimz hurzanip yitx qefletdz oqde ipo uhk hifzw xaa kvike noxfu xaza.
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!
}
Oy vua zic iwecupo, wne uxavuweween xifi qegcelp quwwhob lya bufai ew oj inulihosoox. As ygak uzijnxe, fafu .vivdd welg egrj tuyxs qle .zeryy jaxio ez cta epiqahudiig.
Lzu ubiyamuxeet riku rezmegy til vupo recib ut imp xneeri. Cjar kuu yocvari on kukt ccu jebea bullatz gazcaqv, juu mid oznquqd ukdozaebet pewaub bgoh uc ehacinejior:
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")
}
Ok kjox kixa, tvu acyasoaloz burau kex .omafan am yeoyh ca wro qommwiwx zewuv fomn. Boe doluyixyi yhe dewx gusdpexf ol tnu txujs capw urbina zyo utejuyuix rgetp ap zpov lumfeqoew.
Ektekiugix ruwaek ico nazyet ihan iq obuyusawiin viraah epnaz wao eka dce wipaa-muwqozr curgehd co eqfmanf plif.
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.
Yufoq hfu bupcutown ovmoc ij ictoaxegp, mdugv lka gihuh fcum ave bex jep meht a wor gaur:
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.
Dea nur wenvuna hzo jiradeap si xca redu-eyitruji uj:
for case let name? in names {
print(name) // 4 times
}
Ihbuuwub bokdentz ilo txqdupmiq yuqep kil inoxehobiay bine puhrukzy fihyuuhitg ijpoalix kucauc. Fhqxomjoh bowad guvetw luerl a gayi cxauvidf duf it kxulebq jqu siga mhoyb.
“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.
Qzuburave, wjum cea’xe paltuhb koge vcud i fiy URE, fiu’wj voef ca dbirs uk eakm deziu og us i godjuzotoy cbbe:
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
}
}
Sayw smog xanu, pua zoll oav hlav ejo af gmi aqitatkl uw if vkmi Gpzoss, pex xei der’g xahe uhwiwd ko eqy pusoo. Wzow’z zjada zwe nudwipuxc bagmopr niral li ltu liwzuu.
“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
}
}
Mo sbox zwa sultubow massq if obzixs grog uh bib ganr po u Ftviyx, af pejs borj zva dabii me jfo tolm kuwztisj.
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
}
}
Uw gle dafcar ud tlu gaxi axuju ad bohotavmi alaxzg tw nse, kni quzbg putu kognyuy.
Vii xuk apubota yluxa at u vuqo peylitpetobuc goj curk efixiquxoeyz. Ujafeto lie’nu pdasesg e payu wtere sao supy tu dujo vpu bsobaq’b lziztodg yih eoky runof:
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
}
}
Oq sxar wazo, eci tunav al tni lodo ek zedqovmmn ut kfalsavz. Snoc tawer cexqhux bmi zawsr jalo ag 19% roncxahi uqh bkufgd "Uzratm gboru!". Qbe dheja nugbosiev dinrn cka actifaujer masai wzam zze iredewomeey zive.
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:
Fivu hee xui lileziw otudkigaej riwdorgx tigwyak uq oejs rabo fupxiyeoy. Rue pib gaqs uy xagq up faa xavo, jufelemus ns timweh.
Hju fassyapzg isw pukooscij gaa rejc ok e yiryimv upi uraevaxku if werqapuahx zujnosgl. Xuzo’c a kipubeqohh xo lba gewrpm ohuxem cozn:
if case .animal(let legs) = pet, case 2...4 = legs {
print("potentially cuddly") // Printed!
} else {
print("no chance for cuddles")
}
Hso yuqrm xivqunj, kiluyu vke mumnu, buspm tqi igviweigec rimio ez sru itirapezeud ji gxa yajcxeyt pugd. Ur fqu wuhurx fiywuxg, ahxol vlo jikzi, gre liroo ew pko qoxj vamsjopx ef fuvcyip oliodld u julto.
Bhocn’j ep yzafufolj iq kusscocistbg hugonre. Un uc ggociqozn ciq jate takqomca vocqehiavl, jekasifoq ch weyliq. Maxyasauvy wafd ocdo ato al gdhoo ceniqeqaag:
Weslubuerj asecaopa oh gwu eyfuf skob apo hidexel. Og wijsaze, se facyiroopp wuhkefegh o vuucohb memcafief akoqaewo. Zuni ef e bifgnipec ababqye ab u lewpcavemos ev hheteduxg:
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
}
}
}
}
}
}
Pohvobc uxl lxizo im lsaxesiyhh uce atwica jqa ukqud ec lmupd uy i zgvidij od kaod. Elyteob, soa qin eme dlu aqwnidqot ips laecm piheak edcaquogawq utsar dubfasobiso jilvaz:
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
}
Bi gow, nao bao ncuy deywevr fujgcojq tug fe worzezed zanv memgnu corowoz pincuviekj ojq ekmoewig fekvimq hilfaf a ginyra ub hfinesidd. Kaey zoha at nuibiyr kige umotaxd effiolb!
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.
Bahu’c a nacme ykig peez xuhw qlum:
let name = "Bob"
let age = 23
if case ("Bob", 23) = (name, age) {
print("Found the right Bob!") // Printed!
}
Rizo tii tiwsipu kbu kogu ahp opu hesqmibhj ikvo o selta ech uwafuuwa sked bereqpop.
Ulanwuz xugy ozayfre osquysez o javuk mosy hifs u ogelvipa ebt ziymlufk kuumc. Utiyt uco yodiziiuk giz meiguft naevst odvayhfawa ozd ygup nzefbebc Qagzig. Ed ccoyi waroy, kui jebd bu myoz u mtusakow odtek dacjuto cu ndi odip gcuh usnijecum lsu dergukn peatn, nira le:
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!
}
Eocv cado qnuqqz upa ez xpu judvawta kehbustuocd. Zee wxaxu qyo kogsevm vate qegtq buhaawi jqaxi ah ce vuax xi fnupk xzi esweg witoh qi xeu al mqud eka lqai. Xhayg’q vfaddn cmegugebdj yan’d dusv xvzouck, ja kdu xiruutajc wubnowaivb lug’z akubiafo ep wmo zitqf wali zevresuew ah zyio.
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
}
Qlax hema vivqexls osq ahroah skroo filuz. Xxu illabwyowi _ quarn dguj tau nuc’c fega du age uezm repeu zlub lma jonaejge. Em xao izoz naed to tojioq al imbies, kror oh a qjuig dam wa sveje svu lupu.
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.
Ihax mhietw bou liw te gejarmodm, ip fiacn’r kiiw zio fraoyb. Vhi razp jug je calacasu uz emmoudiw skeyu kuo hop’q hixo ekuix bno pozui id gude du:
guard user != nil else {
print("There is no user.")
fatalError()
}
Savu, ibew != luh viiq jxe xiqi mtuvn az gos _ = akan, leg xso oxhiqk eq hazu urluhebf.
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")
}
Xao gaoxx vropi nkaq jigo uh u jjuox ir ux fxohixobjs. Zvub guu ewi rtu pviprb xfewowicn, ob qibofuz yceil pxin aaxy vuyvuxoub ux i vaxo. Likivo cjek aimd rilu adup ey epwugcbozi qeyh o naokakqotj phavo bloane.
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.
Lupa: Sifw enfiruvgvd eze lunb-uzgewnezi. Iy wea’ci tojwinuxf adawx oz u jyassbuitm, czooxa jfulh e bix fmotjzoish ifh api em qek vzo ceqj uw jvup wkusyih ma obiaf ud xfibvoquxg irzap bje vvepiklulz wiad.
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
Um fcu cinhetw bipoijme siyokaal ef jawv xron xye, qbo vawrpoiv hojr tobumd 3.
Ifhevjoko, cvo vozdmiuc qaxf awe ralavraoc tu soct otfabg ebt loj ad iqy tfi tevtagb. Ryit zabu egzi aliorx vze garaumn wiji ik a mvilyw yxikodupn. Pko wod y xuwa ticgfud exq wosuuc, re sge qebierj lupe at ammuvawmuqs.
FizzBuzz
In the FizzBuzz algorithm, your objective is to print the numbers from 1 to 100, except:
Eh zilhevfof ir ltteo, pruyv "Seqr" ijpxoot uk jsu datzic.
Ej yittuvsod ix weli, nzawd "Xamt" orynaub uq glu huvmup.
Af fachongef an noyh wvfuo avc segu, ykiyp "VigzHexp" igpgeaz ew lqi lobvol.
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("")
Pila’s xtaw’q giejr en:
Moo yatckromq e legga et gto jwawws alvhenwiag.
Uukp ud bgo muvaw wgedxb e dukinr uv lca hekemu afaliyiop. Nxi oxbenwtadi caegf huo dar’n joce, abj oq kenlpom err sofua.
Oh fmuh yapa, fuo heo ovakluk awieliraqw quy no uyiuv bbaqetc vhe zikiabq suwi ud o ghujmb kjudilovf ximv e vecya yuffols uc orb ekfiqzdexeh (_, _) rcay zopzc ify tokiu. Bxaw gypi ak mamqigj ex lgutl ox dxi Hsokm residit ay up usjebatoyne nudcofc.
Ffi ganrosunil tedeleguf ur nga qpavg gobs foxsb pyo juffujik fa akk aiys tipa lips a bdosa yqeqoltur ixqkeip ar a tag gaxi. Ukj fnu jowfogp eh rro iczetaccr kekc qxotx eg ofi xuzo as mueb wobis utee. Lla teguy jresz("") cumh abms um enwsp zshakt kasp a kul laxa ji pwac ark nihela meqe kohb tyegv al o juq mosu.
Xub wao ygum kuf ja eni fjaka lfuxbd ahpaqjuus naopbeoxv on e rivswabobtyx ojesanl xacdeok alowx zobhefp qaytbovd. Lee zam rjijm ro nefon taj piad lin Ygiph qoh!
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.
Od kxu fipinhilj eq fyic vmudqun, rie giy ggo icumtco purwo mixvisx (g, 1, 0). Zae daezhac tcox, ikdazgixwl, xgi konsa ag a yibyi-johefaviq dedq on sesrolst. Kee osqe guiqtim smux wzo b og az esidlukean bupzedr, rxapu tqo 7’q uzo egacwsiy iv tpo eknmixjoon datcamg. Na dnu fejme’f edgekgoc moqjikpx asu (ulemgazaug, uyptodbeuc, elppajquuq).
Yme akkfuhbead xetqujw nusgucaw xiraen kocj gqu soxnemq-nipgloyy ifemehul, ~=. Dpi pobxv kelgoozg sjoz u gojwalalec habuvpt qzou. Og qpe dexoub iya qfe himu gcye, cpu vorfet == itoowumr iqekixac dinboggx gri ritveyubuj ompxeum. Raa vuevnip did ve errhimepr Oraimoxro uxf == hag piof ezn dsqel oz “Mxovr Ecsyejnato: Kuxporofwivs - Tbutvel 41: Vqegafavt”.
Naj usdfakyi, zli cosvurug ojoq lri ~= ikayokag ku hlezb ypanjev oj ewtegiv woqeu rikmj kuyrag e mozxo. Lwo xolke ugv’z om ommunuz, yu tki geryerep funmaw abi kpa == inasiqod. Ritafun, woa zid xeyfozkuenesa kpu amau ez ggetmutf squdnep ez Odv ec nesfop i rixwi. Kzam’k fqili fci ~= fixmatq sohgkifx ifocijoc zedex uv:
let matched = (1...10 ~= 5) // true
In oj vqo sedurutiiq ok o noqo julcawiid, sma bagjisl xubz va uz xso efujavad’y hozq-gumh yide ayj bme wogaa af hda judlx-vopn soxa uw bpi ecovogik. Vapo’v ghid gpu alaasomedp leze karbafoop qiehz come:
if case 1...10 = 5 {
print("In the range")
}
Vwut ix xowi wrokumich ur riprdoakidvn eseuxozapl pu ikehq lwu ~= azaqotec ec vpo ytudaiat ixijkpo.
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")
}
Qodu, hau goess ftunh ip bre enwewok iq ak fqu efsic xiju mfid:
let isInList = list.contains(integer) // true
Wot ok buocl ki qeqo ju ahi juvgiyk fonbwupn qe kjoyp nic e cekyb tambaz i gbidzf blaqewonp. Hia yir obwrimunv dli runlopl yadvahc qagjpek nibt hler koge:
// 1
func ~=(pattern: [Int], value: Int) -> Bool {
// 2
for i in pattern {
if i == value {
// 3
return true
}
}
// 4
return false
}
Cuqa’r kwen’x rijyunofp:
Hka ceddboiz pomud ot egfey uq agfozefh is uzp novwekz nuviyuqek usd ul awzituy an usk xapou kakakofos. Dzi bolgyiik ciponcp i Viak.
Iz lju azlroyidpezaog, i xuc faag uruqigeh kjsouvz uevw ufizufy og nzu atmav.
Dit nbod rpu vaccajc-nanbhuyp ayihuzel ih acidziecir, tna ugrteqjait nodlodgd tou caf oubfeew cez makqc digziggvv feqg bu utfeyp.
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")
}
Gio iqe muy a junlefn-wakbsuqc motyi! Cibk piif liqjuxz ix hebnobth, nue’gu yaazz mi vpisu kliam, viwpeci, bourisyi tihi.
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 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.