Swift can make matching judgments on the values of different data types in switch:
var things = Any[]() (0) (0.0) (42) (3.14159) ("hello") ((3.0, 5.0)) (Movie(name:"Ghostbusters", director:"Ivan Reitman")) for thing in things { switch thing { case 0 as Int: println("zero as an Int") case 0 as Double: println("zero as a Double") case let someInt as Int: println("an integer value of (someInt)") case let someDouble as Double where someDouble > 0: println("a positive double value of (someDouble)") case is Double: println("some other double value that I don't want to print") case let someString as String: println("a string value of "(someString)"") case let (x, y) as (Double, Double): println("an (x, y) point at (x), (y)") case let movie as Movie: println("a movie called '()', dir. ()") default: println("something else") } } // zero as an Int // zero as a Double // an integer value of 42 // a positive double value of 3.14159 // a string value of"hello" // an (x, y) point at 3.0, 5.0 // a movie called 'Ghostbusters', dir. Ivan Reitman
Here it will match according to the value of the thing and enter the corresponding case.
Today I suddenly thought of a question, which made me feel it is necessary to summarize the switch statement. We know that switch in swift is much more powerful than C language to compare integers, but the question is, which types can be compared in switch? Can objects be compared?
The official documentation gives an explanation of the usage of switch:
Cases can match many different patterns, including interval matches, tuples, and casts to a specific type.
In other words, in addition to the most commonly used comparison integers, strings, etc., switch can also be used to match ranges, tuples, convert them into a specific type, etc. But the including in the document is really speechless because it does not specify all types that can be compared in switch, and the questions raised at the beginning of the article still have no answers.
Let's try it out and use switch to match objects:
class A { } var o = A() var o1 = A() var o2 = A() switch o { case o1: print("it is o1") case o2: print("it is o2") default: print("not o1 or o2") }
Sure enough, the compiler reported an error: "Expression pattern of type 'A' cannot match values of type 'A'". At least we don’t understand what “expression pattern” is, so how can type A not match type A.
Let's make some changes and add let after the case statement:
switch o { case let o1: print("it is o1") case let o2: print("it is o2") default: print("not o1 or o2") }
OK, compile and run, the result is: it is o1. This is because the case let does not match the value, but value binding, that is, assigning the value of o to the temporary variable o1, which is useful when o is an optional type, similar to implicitly parsing optional types like if let. It is not typed. It is because the switch in swift only matches the first case, and then it ends. Even if you don't write break, you won't jump to the case behind.
I'm going too far, and I'll come back to the topic. Since adding lets cannot be done, we have to think of other ways. At this time, you might as well consider how the switch statement is implemented. According to my personal guess, it is probably similar to using multiple ifs to determine whether there is a matching case. Since that is the case, let's try to overload the == operator for type A:
class A {} func == (lhs: A, rhs: A) -> Bool { return true } var o = A(); var o1 = A() ;var o2 = A() switch o { case o1: print("it is o1") case o2: print("it is o2") default: print("not o1 or o2") }
Obviously, it failed again. If this can solve the problem, then this article is too miserable. The error message is the same as before. But the problem is that we have overloaded the == operator, why can't type A still match type A? Doesn't switch have to determine whether the two variables are equal?
As a multi-condition matching statement, switch naturally needs to judge whether the variables are equal, but it is not judged by the == operator, but by the ~= operator. Let’s take a look at the explanation of the official document:
An expression pattern represents the value of an expression. Expression patterns appear only in switch statement case labels.
And this sentence:
The expression represented by the expression pattern is compared with the value of an input expression using the Swift standard library ~= operator.
The first sentence explains the previous error report. The so-called "express pattern" refers to the value of the expression. This concept is only found in the switch case tag. So the previous error message said: "The value of the expression o1 (or o1) and the parameter o passed in are of type A, but they cannot match." As for why it cannot match, the answer is in the second sentence, because the matching of o1 and o is done by calling the ~= operator in the standard library.
So, just replace the overload == with the overload ~=. Change a character, don't need to change anything else, and the program can run. Swift calls the == operator in the ~= operator by default, which is why we don't feel that there is any additional processing required to match integer types. But for custom types, if you don't overload the ~= operator, it's useless even if you overload ==.
In addition, there is another solution, which is to let type A implement the Equatable protocol. This way there is no need to overload the ~= operator. The answer is in the last few lines of Swift's module:
@warn_unused_result public func ~=<T : Equatable>(a: T, b: T) -> Bool
Swift has overloaded the ~= operator for all classes that implement the Equatable protocol. Although implementing the Equatable protocol only requires overloading the == operator, if you do not explicitly indicate that you comply with the Equatable protocol, swift cannot know. Therefore, if you overload the == operator, just mark the implementation of the Equatable protocol. This has many benefits, such as the split method of SequenceType.
A final summary:
Types that can be placed in switch statements must overload the ~= operator, or implement the Equatable protocol.