The Swift Enumeration Case Pattern

Jonathan Lehr

|

7 min read
An iphone on a colored background


The Basics


Defining a Trivial Enum
enum Size {
    case small
    case medium
    case large
    case extraLarge
}
enum Size {
    case small, medium, large, extraLarge
}
enum Size: String {
    case small = "S"
    case medium = "M"
    case large = "L"
    case extraLarge = "XL"
let shirtSize = Size.extraLarge
print("Size \(mySize)")
// prints "Size extraLarge"

print("Size \(mySize.rawValue)")
// prints "Size XL"

Switch Statements
switch (shirtSize) {
        case .medium: print("Shirt is size M")
        default: print("Shirt is not size M")
    }


The Pattern


Associated Values
enum Garment {
case tie
case shirt
}
enum Garment {
case tie
case shirt(size: String)
//        ^^^^^^^^^^^^^^
}
let myShirt = Garment.shirt(size: "M")
enum Garment {
case tie
case shirt(size: String)
case pants(waist: Int, inseam: Int)
}

let myPants = Garment.pants(waist: 32, inseam: 34)
switch someGarment {
case .tie: print("tie")
case .shirt: print("shirt")
case .pants: print("pants")
}
// prints "pants"
let items = [
    Garment.tie,
    Garment.shirt(size: "S"),
    Garment.shirt(size: "M"),
    Garment.shirt(size: "L"),
    Garment.pants(waist: 29, inseam: 32),
    Garment.pants(waist: 35, inseam: 34)
]

for item in items {
    switch item {
    case .tie: print("tie")
    case .shirt("M"): print("\(item) may fit")
    case .shirt("L"): print("\(item) may fit")
    case .shirt: print("\(item) won't fit")
    case .pants(34, 34): print("\(item) may fit")
    case .pants(35, 34): print("\(item) may fit")
    case .pants: print("\(item) won't fit")
    }
}
// tie
// shirt("S") won't fit
// shirt("M") may fit
// shirt("L") may fit
// pants(waist: 29, inseam: 32) won't fit
// pants(waist: 35, inseam: 34) may fit
let myPants = Garment.pants(waist: 32, inseam: 34)

switch someGarment {
case .tie: print("tie")
case .shirt(let s): print("shirt, size: \(s)")
case .pants(let w, let i): print("pants, size \(w) X \(i)")
}
// pants, size 32 X 34
switch someGarment {
case .tie: print("tie")
case let .shirt(s): print("shirt, size: \(s)")
case let .pants(w, i): print ("pants, size \(w) X \(i)")
}
// pants, size 32 X 34
switch someGarment {
case let .pants(w, i) where w == 32: print("inseam: \(i)")
default: print("No match")
}
// inseam: 34

Other Pattern-Matching Capabilities

Strings
struct Song {
    var title: String
    var artist: String
}

let aria = Song(title: "Donna non vidi mai", artist: "Luciano Pavarotti")

switch(aria.artist) {
case "Luciano Pavarotti": print(aria)
default: print("No match")
}
// Song(title: "Donna non vidi mai", artist: "Luciano Pavarotti")

Intervals
let numbers = [-1, 3, 9, 42]
for number in numbers {
    switch(number) {
    case ..<3: print("less than 3")
    case 3: print("3")
    case 4...9: print("4 through 9")
    default: print("greater than 10")
    }
}
// less than 3
// 3
// 4 through 9
// greater than 10

Tuples
let dogs = [(name: "Rover", breed: "Lab", age: 2),
            (name: "Spot", breed: "Beagle", age: 2),
            (name: "Pugsly", breed: "Pug", age: 9),
            (name: "Biff", breed: "Pug", age: 5)]

for dog in dogs {
    switch (dog) {
    case (_, "Lab", ...3): print("matched a young Lab named \(dog.name)")
    case (_, "Pug", 8...): print("matched an older Pug named \(dog.name)")
    default: print("no match for \(dog.age) year old \(dog.breed)")
    }
}
// matched a young Lab named Rover
// no match for 2 year old Beagle
// matched an older Pug named Pugsly
// no match for 5 year old Pug

Type Casting
struct Dog {
    var name: String
}

let items: [Any] = [Dog(name: "Rover"), 42, 99, "Hello", (0, 0)]

for item in items {
    switch(item) {
    case is Dog: print("Nice doggie")
    case 42 as Int: print("integer 42")
    case let i as Int: print("integer \(i)")
    case let s as String: print("string with value: \(s)")
    default: print("something else")
    }
}
// Nice doggie
// integer 42
// integer 99
// string with value: Hello
// something else


Case Conditions


Case Conditions in Branches
let someColor = "Red"

switch someColor {
    case "Red": // do something here
    // ...
if case "Red" = someColor {
    // do something here
}
if someColor == "Red" {
    // do something here
}
let Garment.shirt(size: "XL")
let items = [
    Garment.tie,
    Garment.shirt(size: "M"),
    Garment.shirt(size: "L"),
    Garment.shirt(size: "XL"),
    Garment.pants(waist: 32, inseam: 34)
]

for item in items {
    if case .shirt = item { print(item) }
}
// shirt: M
// shirt: L
// shirt: XL
for item in items {
    if case .shirt("XL") = item { print(item) }
}
// shirt: XL
for item in items {
    if case let .shirt(size) = item, size.contains("L") {
        print(item)
    }
}
// shirt: L
// shirt: XL
let Garment.shirt(size: "XL")

Case Conditions in Loops
for case .shirt("XL") in items {
    print("shirt, size XL")
}
// shirt, size XL

for case let .shirt(size) in items where size.contains("L") {
    print("shirt, size \(size)")
}
// shirt, size L
// shirt, size XL
let items:[Garment] = [
    .tie,
    .shirt(size: "L"),
    .pants(waist: 35, inseam: 31),
    .pants(waist: 35, inseam: 34),
    .pants(waist: 35, inseam: 35),
]

for case let .pants(w, i) in items where w == 35 && 34...36 ~= i {
    print("pants, \(w) X \(i)")
}
// pants, 35 X 34
// pants, 35 X 35


Conclusion

Newsletter Form
  • VA ProdOps and Data Quality Engineering
    VA ProdOps and Data Quality Engineering
    See more: VA ProdOps and Data Quality Engineering
    Small orange arrow symbol
  • Where the future is going: sniffing out all of Apple’s clues
    Where the future is going: sniffing out all of Apple’s clues
    See more: Where the future is going: sniffing out all of Apple’s clues
    Small orange arrow symbol
Abstract graffiti-style artwork with vivid colors and dynamic shapes.
Simple Form

Connect with our team.

Error

An error has occured, please try again.

Try again