Pattern matching
Pattern matching is a very common programming pattern in Swift. Using pattern matching can help us write concise, clear and easy to read code, making our code concise and powerful.
Pattern matching in conditional judgment
Conditional judgment is the most common process control we use. In Swift, we can only accept Bool type values as conditional bodies; in addition to directly judging Bool values, we can also use conditional statements for optional binding, which is a very common way in our development.
Match enum values
In Swift, the enum types created are incomparable by default (the Comparable protocol is not implemented), which means that we cannot directly use the == operator to determine whether the two enum values are equal. In this case, pattern matching is required:
Create an enum type:
enum Result { case success case failure }
Initialize an enum value:
let result =
Use pattern matching to determine the value of the created enum value:
if case .success = result { print("Value of result is success.") }
Optional binding
Create an optional value:
let optionalInt: Int? = 1
Unpacking using optional binding:
if let val = optionalInt { print("The value of optionalInt is (val)") } func handleGuard() { guard let val = optionalInt else { return } print("The value of optionalInt is (val)") } handleGuard()
Another mode of optional binding, which is also the most basic mode of optional binding:
if case .some(let val) = optionalInt { print("The value of optionalInt is (val)") }
It can also be simplified to:
if case let val? = optionalInt { print("The value of optionalInt is (val)") }
Pattern matching in loop
The question is, the optional binding of the if let mode can only implement the binding of one optional value. What if we need to match the optional value in an array? At this time, we cannot use the form of if let, we need to use the form of if case let
Create an array with optional values:
let values: [Int?] = [1, nil, 3, nil, 5, nil, 7, nil, 9, nil]
Perform a traversal:
for val in values { print("Value in values is (String(describing: val))") }
or:
var valuesIterator = () while let val = () { print("Value in values is (String(describing: val))") }
We get all the values with optional values, if we need to filter the optional values, we can do this:
for val in ({ $0 }) { print("Value in values is (val)") }
This increases the time complexity and requires two traversals to filter out the data. We can do this using pattern matching:
for case let val? in values { print("Value in values is (val)") }
or:
valuesIterator = () while let val = (), val != nil { print("Value in values is (String(describing: val))") }
This way, the nil value can be filtered. Isn't it very simple? You can also use for case to match an enum value array:
let results: [Result] = [.success, .failure] for case .success in results { print("Values in results contains success.") break }
For complex enum types:
enum NetResource {
case http(resource: String)
case ftp(resource: String)
}
let nets: [NetResource] = [.http(resource: ""), .http(resource: ""), .ftp(resource: ftp://192.0.0.1)]
Filter the value of http:
for case .http(let resource) in nets { print("HTTP resource (resource)") }
for loop using where clause
In addition, we can also follow a where clause to pattern matching in the for loop:
for notNilValue in values where notNilValue != nil { print("Not nil value: (String(describing: notNilValue!))") }
Query all numbers in an array that can be divisible by 3:
let rangeValues = Array(0...999) for threeDivideValue in rangeValues where threeDivideValue % 3 == 0 { print("Three devide value: (threeDivideValue)") }
Query all numbers containing 3:
for containsThree in rangeValues where String(containsThree).contains("3") { print("Value contains three: (containsThree)") }
Pattern matching in Switch
Pattern matching in Switch is also very commonly used. Using pattern matching rationally in Switch can bring us many benefits, which can make our code more concise, while reducing the amount of code and increasing development efficiency.
Interval matching
let value = 188 switch value { case 0..<50: print("The value is in range [0, 50)") case 50..<100: print("The value is in range [50, 100)") case 100..<150: print("The value is in range [100, 150)") case 150..<200: print("The value is in range [150, 200)") case 200...: print("The value is in range [200, ") default: break } // The value is in range [150, 200)
Match tuple type
Create a tuple type:
let tuples: (Int, String) = (httpCode: 404, status: "Not Found.")
Making a match:
switch tuples { case (400..., let status): print("The http code is 40x, http status is (status)") default: break }
Create a point:
let somePoint = (1, 1)
Making a match:
switch somePoint { case (0, 0): print("(somePoint) is at the origin") case (_, 0): print("(somePoint) is on the x-axis") case (0, _): print("(somePoint) is on the y-axis") case (-2...2, -2...2): print("(somePoint) is inside the box") default: print("(somePoint) is outside of the box") }
As above, we can use underscore_ to ignore the value when matching:
switch tuples { case (404, _): print("The http code is 404 not found.") default: break }
Use where clause in switch case
Using where clauses in case can make our pattern matching look more streamlined and make the matching patterns more compact:
let yetAnotherPoint = (1, -1) switch yetAnotherPoint { case let (x, y) where x == y: print("((x), (y)) is on the line x == y") case let (x, y) where x == -y: print("((x), (y)) is on the line x == -y") case let (x, y): print("((x), (y)) is just some arbitrary point") }
Summarize
Types of pattern matching in Swift
Pattern matching can be said to be a very powerful programming pattern in Swift. Using good pattern matching can help us write brief and elegant code. Pattern matching in Swift includes the following types:
- Conditional judgment: if, guard
- Optional binding: if let, guard let, while let...
- Loop body: for, while, repeat while
- switch
- do catch
When to use the where clause?
We can see in the previous example that in many places where pattern matching is used, the where clause is also used. The function of the where clause is equivalent to adding conditional restrictions on the basis of pattern matching. Using the where clause is equivalent to:
for notNilValue in values { if notNilValue != nil { print("Not nil value: (String(describing: notNilValue!))") } }
It can be seen that using the where clause can make our code more concise and easy to read. When to use where? Or where can I use where? The Swift documentation does not introduce the detailed use of where, but in practice, it is found that where can be used in the following places:
- for loop statement
- switch branch
For if, guard and while, we cannot add where clauses after them, because they can combine multiple conditions themselves. Another usage of where clause is to type constraints on generic types, which will be introduced in the generic chapter.
Okay, the above is the entire content of this article. I hope that the content of this article has a certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.