In Swift, pattern matching is a powerful feature that can be used to match values against a set of patterns, including ranges, optionals, tuples, and enums. With pattern matching, you can write more concise and expressive code that is easier to read and maintain.
Pattern matching is commonly used in control flow statements such as switch
and if
statements, but it can also be used in other contexts such as function parameters and variable binding.
The most basic pattern matching in Swift is the switch statement.
let number = 5
switch number {
case 1:
print("The number is 1")
case 2:
print("The number is 2")
case 3, 4:
print("The number is 3 or 4")
default:
print("The number is not 1, 2, 3, or 4")
}
One of the most useful features of pattern matching in Swift is the ability to match ranges of values.
let age = 25
switch age {
case 0..<18:
print("You are not an adult")
case 18..<21:
print("You are a young adult")
case 21..<30:
print("You are in your 20s")
default:
print("You are 30 or older")
}
let optionalName: String? = "John"
if let name = optionalName {
print("Hello, \(name)!")
} else {
print("Hello, stranger.")
}
You can also use the if case
syntax to match additional conditions in a pattern:
let name: String? = "John"
if case .some(let value) = name, value == "John" {
print("The name is John")
}
let coordinates = (x: 10, y: 20)
switch coordinates {
case (0, 0):
print("The coordinates are at the origin")
case (_, 0):
print("The coordinates are on the x-axis")
case (0, _):
print("The coordinates are on the y-axis")
case (let x, let y) where x == y:
print("The coordinates are on the line y = x")
default:
print("The coordinates")
}
You can use a wildcard pattern (_) to match any value in a tuple.
let tuple = (42, "hello", true)
switch tuple {
case (_, _, true):
print("The third value is true")
default:
print("The third value is false or not a Bool")
}
enum Result {
case success(Int)
case failure(Error)
}
let result = Result.success(42)
switch result {
case .success(let value):
print("The result is a success with value \(value)")
case .failure(let error):
print("The result is a failure with error \(error)")
}
let person = (name: "John", age: 25)
switch person {
case ("John", _):
print("Hello, John!")
case (_, let age) where age < 18:
print("You're too young, sorry.")
case (_, let age) where age >= 18:
print("Welcome!")
default:
break
}
Expression patterns are used to match a value against a specific expression. The expression can be a constant, variable, function call, or any other valid expression in Swift.
let value = 42
switch value {
case 0...10:
print("The value is between 0 and 10")
case 11...20:
print("The value is between 11 and 20")
case 21...30:
print("The value is between 21 and 30")
case let x where x % 2 == 0:
print("The value is an even number")
default:
print("The value is something else")
}
// Output: The value is an even number
The fourth case uses an expression pattern with a where
clause to match any even number. The pattern matches if the value
is divisible by 2 with no remainder.
The wildcard pattern is used to match any value without binding it to a variable or constant. It’s denoted by an underscore (_) character, which acts as a placeholder for any value.
let value = "hello"
switch value {
case "goodbye":
print("The value is 'goodbye'")
case _:
print("The value is something else")
}
The second pattern uses a wildcard pattern to match any other value. Since the wildcard pattern doesn’t bind the value to a variable or constant, we can’t use the matched value in the print
statement.
You can overload the ~=
operator to provide custom expression matching behavior.
// Overload the ~= operator to match a string with an integer.
func ~= (pattern: String, value: Int) -> Bool {
return pattern == "\(value)"
}
let point = (1, 2)
switch point {
case ("0", "0"):
print("(0, 0) is at the origin.")
default:
print("The point is at (\(point.0), \(point.1)).")
}
// Prints "The point is at (1, 2)."