Chaining with commas
In Chapter 5, “Advanced Control Flow” you learned how to match more than one pattern in a single case condition. Here’s an example similar to what you saw in that chapter:
func timeOfDayDescription(hour: Int) -> String { switch hour {
case 0, 1, 2, 3, 4, 5:
return "Early morning" case 6, 7, 8, 9, 10, 11:
return "Morning"
case 12, 13, 14, 15, 16:
return "Afternoon" case 17, 18, 19:
return "Evening" case 20, 21, 22, 23:
return "Late evening" default:
return "INVALID HOUR!"
}
}
let timeOfDay = timeOfDayDescription(hour: 12) // Afternoon
Here you see several identifier patterns matched in each case condition. You can use the constants and variables you bind in preceding patterns in the patterns that follow after each comma. Here’s a refinement to the cuddly animal test:
if case .animal(let legs) = pet, case 2...4 = legs { print("potentially cuddly") // Printed!
} else {
print("no chance for cuddles")
}
The first pattern, before the comma, binds the associated value of the enumeration to the constant legs. In the second pattern, after the comma, the value of the legs constant is matched against a range.
Swift’s if statement is surprisingly capable. An if statement can have multiple conditions, separated by commas. Conditions fall into one of three categories:
- Simple logical test E.g.: foo == 10 || bar > baz.
- Optional binding E.g.: let foo = maybeFoo.
- Pattern matching E.g.: case .bar(let something) = theValue.
Conditions are evaluated in the order they are defined. At runtime, no conditions following a failing condition will be evaluated. Here is a contrived example of a complicated if statement:
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)") // Printed: 26
}
}
}
}
}
}
Nesting all those if statements one inside the other is called a “pyramid of doom”. Instead, you can use the unwrapped and bound values immediately after consecutive commas:
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
}
So now you see that pattern matching can be combined with simple logical conditions and optional binding within a single if statement. Your code is looking more elegant already!