In addition to the basic loop and branch controls we mentioned in the previous section, the judgment conditions we need in real life may be more complex than those demonstrated in the examples. Swift does this by borrowing style matching from functional programming to help us build code that is rich in meaning and easy to maintain. In this section, we’ll look at some basic style matching methods used in branch and loop control statements.

The way values are matched

To demonstrate the various styles of matching, let’s define a tuple that represents the origin in a plane rectangular coordinate system:

let origin = (x: 0, y: 0)
Copy the code

Now, the primitive way to determine if a point is the origin is this:

let pt1 = (x: 0, y: 0)

if pt1.x == origin.x && pt1.y == origin.y {
    print("@Origin")
}
Copy the code

Of course, this is not a very satisfying way to determine whether the x and y coordinates are the same, and it’s very cumbersome to write. In fact, we can do this:

if case (0, 0) = pt1 {
    print("@Origin")
}
Copy the code

We can determine the object to be examined by using the case matching value = the object to be examined. In our case, it’s whether pT1 is equal to the origin.

In addition to matching values in if, we can also match values of a particular form in the Case branch of the switch:

switch pt1 { case (0, 0): print("@origin") case (_, 0): print("on x axis") case (0, _): print("on y axis") case (-1... 1, 1... 1): print("inside 1x1 square") default: break }Copy the code

In this example, instead of using case (0, 0) to match the origin value, we can also use (_, 0) and (0, _) to match only one part of the tuple, or, at each member of the tuple, Matches a range of values using the range operator.

In addition to using case for conditional branch statements, we can also use case for loop statements to further control loop conditions, for example:

let array1 = [1, 1, 2, 2, 2]

for case 2 in array1 {
    print("found two") // Three times
}
Copy the code

In the example above, we print a line to the console when we encounter an element of the array with a value of 2, so print prints three times.

Bind the matched content to the variable

In addition to using various forms of concrete values in a case, we can also bind the matched contents directly to variables so that we can use them directly in the corresponding processing code, for example:

switch pt1 {
case (let x, 0):
    print("(\(x), 0) is on x axis")
case (0, let y):
    print("(0, \(y)) is on y axis")
default:
    break
}
Copy the code

In the example above, we replace the _ part with let x and let y, so that, again, we can directly access the matched value in the corresponding case. We call this form a value binding.

In addition to directly binding the value of the variable itself, we can similarly bind the associated value in enum. For example, let’s define an enum that represents the direction

enum Direction {
    case north, south, east, west(abbr: String)
}

let west = Direction.west(abbr: "W")
Copy the code

For demonstration purposes, we add an associated value to.west, short for direction. Then, we can either judge the enum value itself like this:

if case .west = west {
    print(west) // west("W")
}
Copy the code

In this case, print prints the value of enum case. We can also directly bind west’s associated value as follows:

if case .west(let direction) = west {
    print(direction) // W
}
Copy the code

In this case, the value printed by print is the character “W”. Of course, the use of case in the switch branch is also perfectly acceptable.

Automatically extracts optional values

In addition to binding the associated value of enum, we can also use case to automatically extract non-null values of optional type:

let skills: [String?]  = ["Swift", nil, "PHP", "JavaScirpt", nil] for case let skill? in skills { print(skill) // Swift PHP JavaScript }Copy the code

In our example, skills contains five elements, two of which are nil, and when we use case let skill? When you bind optional values in this form, Swift will automatically extract every non-nil element, so print will print “Swift PHP JavaScript”.

Automatically bind the result of the type conversion

The last basic class of style matching rules is the result of automatically binding type conversions. First, we create an [Any] :

Let someValues: [Any] = [1, 1.0, "One"]Copy the code

When we iterate over someValues and want to do something for each type of array element, we can do something like this:

for value in someValues { switch value { case let v as Int: print("Integer \(v)") case let v as Double: print("Double \(v)") case let v as String: print("String \(v)") default: Print ("Invalid value")}} // Integer 1 // Double 1.0 // String OneCopy the code

In the above example, we use case let Variable as Type to bind the result of successful Type conversion to Variable V. This way, we can access the converted value in the corresponding case.

Or, if you just want to determine the type without knowing the content, you can use the simpler IS operator:

for value in someValues {
    switch value {
    case is Int:
        print("Integer")
    // omit for simplicity...
}
Copy the code

Thus, when the array element type is Int, we print “Integer” to the console.

What’s next?

So, in Swift, we bind values in various ways to simplify code usage in branch judgments and loop statements. Simply, we can bind values, bind associated values, bind optional unwrapping results, bind objects after type conversion. This may seem powerful, but there’s more to the story than that. In the next section, we’ll go a step further and share more advanced style matching methods.