Like the comment and hope it gets better and better with your help

Author: @ios growth refers to north, this article was first published in the public number iOS growth refers to north, welcome to the correction

Please contact me if there is a need to reprint, remember to contact oh!!

This is the third day of my participation in Gwen Challenge

The author briefly describes the usage of Switch in Swift in Day13-SWIFT Foundation summary, 1. Along the way, today we’ll explore the use of pattern matching in Swift, focusing on the implementation in Switch.

Wildcard mode

The wildcard pattern consists of an underscore (_) and is used to match and ignore any value. You can use this pattern when you want to ignore matched values.

This pattern is used when we are dealing with enumerations or primitives with associated values, and when we want to ignore some match value

/ / the enumeration
enum Response {
    case error(Int.String)
    case success
}
let httpResponse = Response.error(300."Network Error")
switch httpResponse {
case let .error(_,  status):
    print("HTTP Error: \(status)")
case .success:
    print("HTTP Request was successful")}/ / tuples
switch (15."example".3.14) {
  case (_._.let pi):
  print ("pi: \(pi)")}Copy the code

An uncommon example is to take advantage of this pattern for optional unpacking, which can be done by attaching? To match the optional so that it becomes _? :

let p: String? = ""
switch p {
case _?:
    print("p = ", p as Any)
case nil:
    print("no words")}Copy the code

For more on the options in Swift, check out my previous Day12 – Optional

Identifier pattern

The identifier pattern can match any value and bind a variable or constant that matches.

For determining a match, use Switch instead of if… Else code is more readable:

let name = "Harry"
switch name {
case "Harry":
    print("Harry")
case "iOS":
    print("Growth is north.")
default:
    print("Harry Potter")}Copy the code

Value binding mode

The value binding mode binds the matched value to a variable or constant.

We can use the value binding pattern to match other patterns, for example, when we implement a method that implements user login functionality

func usernameAndPassword(a) 
    -> (username: String, password: String)? {
      // Get the account/password
}
func usernameAndPassword(a)
    -> (username: String, password: String)? {
      // Get the account/password
    return (username: "IOS growth is north", password: "123123")}switch usernameAndPassword() {
case let (username, _)? where username = = "IOS growth is north":
    attention()
default:
    like()
}

func attention(a) {
    / / concern
}

func like(a) {
    / / thumb up
}

Copy the code

You can do certain things for certain login accounts or passwords.

A tuple pattern

A tuple pattern is a list of zero or more patterns, delimited by a pair of parentheses. The tuple pattern matches the tuple type value of the response.

For data with multiple conditions, we can use meta-ancestor to match the conditions we need:

let age = 23
let job: String? = "Operator"
let payload: Any = NSDictionary(a)switch (age, job, payload) {
case (let age, _?._ as NSDictionary) :print(age)
default: ()}Copy the code

An aside:

A new way to exchange two data using primitives

func swapTwoInTuple(_ x: inout Int._ y: inout Int ) {
 (y, x) = (x, y)
}

var x = 10, y = 20

swapTwoInTuple(&x, &y)
Copy the code

Enumerate use case patterns

The enumeration use case pattern matches a use case of an existing enumeration type. This is probably the most common matching pattern in the Switch. As for the matching of enumerated use cases in Switch, the main concern here is the association value of enumerated use cases. Like the tuple pattern, we can make various conditional judgments on the association value.

enum Response {
    case error(Int.String)
    case success
}
let httpResponse = Response.error(300."Network Error")
switch httpResponse {
case let .error(errorCode, status) where errorCode > = 300 && errorCode < 399 :
    print("HTTP Error: \(status)")
case let .error(errorCode, status) where errorCode > = 400 && errorCode < 499 :
    print("HTTP Error: \(status)")
case let .error(errorCode, status) where errorCode > = 500 && errorCode < 599 :
    print("HTTP Error: \(status)")
case .success:
    print("HTTP Request was successful")
default:()
}
Copy the code

Type conversion mode

There are two types of conversion modes, IS mode and AS mode. Is mode only appears in the Case of Switch statements.

Is modelThe as model

  • Is mode matches a value only if its type at run time is the same as, or is a subclass of, the type specified on the right-hand side of is mode. The IS mode and the IS operator behave similarly in that they both perform type conversions, but the IS mode ignores the returned type. So is mode cannot use value binding

  • In AS mode, this value is matched only if a worthy type is the same type or a subclass of the type specified on the right side of the AS mode at runtime. If the match is successful, the matched worthy type is returned as the type specified on the right side of the AS mode

The following simple example illustrates the difference

let num: Any = 5
switch num {
case is Int:
  print (a + 1)
case let n as Double:
  print (n + 1)
default: ()}Copy the code

Expression pattern

Patterns of expression are very powerful. It matches the value of the Switch with an expression that implements the ~ = operator. This operator has default implementations, such as ranges and arrays. In previous lessons we learned about matching ranges:

let wavelength = 620

switch wavelength {
case 380..<450:
    print("Purple!")
case 450..<495:
    print("Blue!")
default:
    print("Not in visible spectrum")}Copy the code

Array matching is another good example

let myArray = [1.2.4.3]
switch myArray {
case [..0.0.0] :// End with three zeros
case [4..] :// Start with 4
case [_.2._.3] :// the second and the fourth are 2,3
case [_._.8] :// The third number is 8
default: ()}Copy the code

For classes that themselves support the ~ = operator, for custom classes, we can customize the ~ = operator to match the response. The function that implements ~= looks like this, with PatternType and PredicateType that can be replaced with whatever type you want:

func ~ =(pattern: PatternType.predicate: PredicateType) -> Bool
Copy the code

Let’s try the following example

struct Person {
    var money: Int
}

func ~ =(pattern: Range<Int>, predicate: Person) -> Bool {
    return pattern.contains(predicate.money)
}
var reader: Person = Person(money: 1000)

switch reader {
case 0..<1000:
    print("我")
case 1000..<5000:
    print("Liked.")
case 5000..<10000:
    print("Shared")
default:
    print("Concerned")}Copy the code

For more on operator overloading, see the in-depth understanding of Swift Operators I wrote earlier

The switch or the if?

In control flow or when making conditional judgments. How do we choose, switch or if?

  • For enumeration type matching, switch is the natural choice. Because Swift requires that its switch statement be exhaustive. In cases where default is not applicable, switch provides more code integrity and ensures no omissions.

    In general, if is better than switch if there are only two types, unless there is some other operation logic

  • When you use switch to check if a value has more than one possible result, the value is read only once, whereas if is read multiple times. This becomes especially important when using function calls, some of which can be slow.

    Although when making a function call, we usually get the value first and then make a statement judgment

  • Switch supports tuples, ranges, value binding, and WHERE, as well as pattern matching, and is generally recommended when dealing with complex conditions.


If you have any questions, please comment directly, and feel free to express anything wrong with the article. If you wish, you can spread the word by sharing this article.

Thank you for reading this! 🚀