When you use pattern matching in Swift, the compiler uses the ~=
operator behind the scenes to match the value against each case pattern.
By default, the ~=
operator compares two values of the same type using the == operator. It can also match a value with a range of values, by checking whether the value is contained within the range.
The Swift Standard Library provides default implementations of the ~=
operator for several built-in types, such as Int, String, and Optional, but developers can also define their own implementations of the operator for custom types or custom pattern matching logic.
To overload the ~=
operator in Swift, you need to define a function that takes two parameters: a value to match and a pattern to match against.
Here are some examples to demonstrate how this works:
func ~=<T>(pattern: [T], value: T) -> Bool {
return pattern.contains(value)
}
let fruits = ["apple", "banana", "orange"]
let fruit = "banana"
if case fruit = fruits {
print("The fruit is in the list")
} else {
print("The fruit is not in the list")
}
In this example, we’ve defined an overload for the ~=
operator that matches a value against an array pattern. The function takes an array pattern
and a value
, and returns true
if the value is contained in the pattern. We then use this operator overload in a case statement to match a string fruit
against an array of fruits
, and print a message indicating whether the fruit
is in the list or not.
func ~=<T: Comparable>(pattern: ClosedRange<T>, value: T) -> Bool {
return pattern.contains(value)
}
let number = 5
if case 1...10 = number {
print("The number is in the range")
} else {
print("The number is outside the range")
}
In this example, The overload function takes a ClosedRange
pattern
and a value
, and returns true
if the value
is contained within the pattern
.
import Foundation
func ~= (pattern: NSRegularExpression, value: String) -> Bool {
return pattern.firstMatch(in: value, range: NSRange(value.startIndex..., in: value)) != nil
}
let email = "johndoe@example.com"
if let regex = try? NSRegularExpression(pattern: "[a-z]+@[a-z]+\\.[a-z]+") {
if case regex = email {
print("The email is valid")
} else {
print("The email is invalid")
}
}
// Prints: The email is valid
In this example, the overload function takes an NSRegularExpression pattern
and a String value
, and returns true
if the value
matches the regular expression.
protocol MyPattern {
associatedtype Input
func matches(_ value: Input) -> Bool
}
func ~=<P: MyPattern>(pattern: P, value: P.Input) -> Bool {
return pattern.matches(value)
}
struct MyIntPattern: MyPattern {
typealias Input = Int
let patternValue: Int
func matches(_ value: Int) -> Bool {
return value % patternValue == 0
}
init(_ patternValue: Int) {
self.patternValue = patternValue
}
}
let number = 10
if case MyIntPattern(5) = number {
print("\(number) is a multiple of 5")
} else {
print("\(number) is not a multiple of 5")
}
// Prints: 10 is a multiple of 5
In this example, we define a protocol MyPattern. Then we overload the ~=
operator to work with any type that conforms to the MyPattern protocol. Finally, we define a concrete implementation of the MyPattern protocol with MyIntPattern. It takes an Int pattern value and checks whether a given value is a multiple of the pattern.