.
来至于Ray Wenderlich
的《Swift Apprentice》中的Pattern matching
章节的笔记。
https://www.raywenderlich.com/134844/pattern-matching-in-swift
Basic pattern matching if and guard 匹配元组
1 2 3 4 5 6 7 8 9 func process(point: (x: Int, y:Int, z:Int)) -> String { if case (0, 0, 0) = point { return "At origin" } return "Not at origin" } let point = (x:0, y:0, z:0) let response = process(point: pint)
1 2 3 4 5 6 func process (point : (x : Int , y :Int , z :Int) ) -> String { guarde case (0 , 0 , 0 ) = point else { return "Not at origin" } return "At origin" }
Switch 1 2 3 4 5 6 7 8 9 10 11 12 13 14 let closeRange = - 2 ... 2 let midRange = - 5 ... 5 switch point {case (0 , 0 , 0 ): return "At origin" case (closeRange, closeRange, closeRange): return "Nearby origin" case (midRnage, midRnage, midRnage): return "Not ear origin" } let point = (x:15 , y:5 , z:3 )let response = process(point: point)
Switch可以匹配多种情况,Switch
可以匹配范围。 找到第一个匹配值以后,Switch
会退出。
for 1 2 3 4 let groupSizes = [1 , 5 , 4 ,6 , 2 , 1 , 3 ]for case 1 in groupSize { print ("Found an individual" ) }
Patterns Wildcard pattern 检查点是不是在x轴上。
1 2 3 if case (_ , 0 , 0 ) = coordinate { print ("on the x-axis" ) }
Value-binding pattern 检查点是不是在x轴上面,并且得到x的值。
1 2 3 if case (let x, 0 , 0 ) = coordinate { print ("On the x-axis at \(x) " ) }
对于你要得到多个值的情况,你可以直接把let
写在括号外,switch获得枚举值的时候,也是可以把let或者var写在外面。
1 2 3 if case let (x, y, 0 ) = coordinate { print ("On the x-y plane at (\(x) , \(y) )" ) }
Enumeration case pattern 1 2 3 4 5 6 7 8 9 10 enum Direction { case north, south, east, west } let heading = Direction .northif case .north = heading { print ("Don't forget your jacket" ) }
这个也可以用在处理错误的时候,传递相关的错误信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 enum Organism { case plant case animal(legs: Int ) } let pet = Organism .animal(legs: 4 )switch pet {case .animal(let legs): print ("ok" ) default : print ("ok" ) }
Optional pattern 当数组包含Optional
的值,可以通过这种syntactic sugar
来获取里面的值并且解包。
1 2 3 for case let name? in names { print (name) }
“Is” type-casting pattern 用is检查是不是特定的类型,多用在JSON的解析。
1 2 3 4 5 6 7 8 9 10 let array: [Any ] = [15 , "George" , 2.0 ]for element in array { switch element { case is String : print ("ok" ) default : print ("123" ) } }
“As” type-casting pattern 当element是string
类型,运行下面语句。并将值赋值给text
变量
1 2 3 4 5 6 7 8 for element in array { switch element { case let text as String : print ("Found a string:\(text) " ) default : print ("Found something else" ) } }
Advanced patterns ###Qualifying with where 传入的值可以被2整除
1 2 3 4 5 6 7 8 for number in 1 ... 9 { switch number { case let x where x % 2 == 0 : print ("even" ) default : print ("odd" ) } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 enum LevelStatus { case complete case inProgress(percent: Double ) case notStarted } let leves: [LevelStatus ] = [.complete, .inProgress(percent:0.9 ), .notStarted]for level in levels { switch level { case .inProgress(let percent) where percent > 0.8 : print ("Almost there!" ) case .inProgress(let percent) where percent > 0.5 : print ("Halfway there!" ) case .inProgress(let precent) where percent > 0.2 : print ("Made it throug the beginning!" ) default : break } }
Chaining with commas 用都好匹配多个值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 func timeOfDayDescription (hour : Int ) -> String { switch hour { case 0 , 1 , 2 , 3 , 4 , 5 : return "Early morning" case 6 , 7 , 8 , 9 , 10 , 11 : return "Morning" case 12 , 13 , 14 , 15 , 16 : return "Afternoon" case 17 , 18 , 19 : return "Late evening" default : return "INVALID HOUR!" } }
首先匹配pet
是不是动物,然后在匹配这个动物的腿是不是在2…4之间。
1 2 3 4 5 if case .animal(let legs) = pet, case 2 ... 4 = legs { print ("potentially cuddly" ) } else { print ("no change for cuddles" ) }
Swift
的if
申明,用途相当广
Simple logical test foot == 10 || bar > baz
Optional binding let foot = maybeFoo
Pattern matching cas .bar(let something) = theValue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 enum Number { case integerValue(Int ) case doubleValue(Double ) case booleanValue(Bool ) } let a = 5 let b = 6 let c : Number ? = .integerValue(7 )let d: Number ? = .integerValue(8 )if a != b { if let c = c { if let d = d { if case .integervalue(let cValue) = c { if case .integerValue(let dValue) = d { if dValue > cValue { print ("some code" ) } } } } } }
在Swift
中我们可以简写成如下代码,和guard功能类似,有可以把if
金字塔式的结构给流水化。下面的代码只要有一个不满足,那么if就不成立。
1 2 3 4 5 6 7 8 if a != b, let c = c, let d = d, case .integervalue(let cValue) = c, case .integerValue(let dValue) = d, dValue > cValue { print ("some code" ) }
Custom tuple 1 2 3 4 5 6 let name = "Bob" let age = 23 if case ("Bob" , 23 ) = (name, age) { print () }
1 2 3 4 5 6 7 8 9 10 11 12 var username: String ?var password: String ?switch (username, password) {case let (username? , password? ): print ("Success" ) case let (username? , nil ): print ("Password is missing" ) case let (nil , password): print ("Username is missing" ) case (nil , nil ): print ("Both username and password are missing" ) }
Fun with wildcards Do something multiple times 1 2 3 for _ in 1 ... 3 { print ("hi" ) }
_
意味着你不关心里面的值是什么。
Validate that an optional exists 1 2 3 4 let user: String ? = "Bob" guard let _ = user else { print ("There is no user." ) }
检查optional
是否有值。
1 2 3 guard user != nil else { print ("There is no user." ) }
Organize an if-else-if 用switch
代替在OC
中的if else
的结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 struct Rectangle { let width: Int let height: Int let color: String } let view = Rectangle (width:15 , height:60 , color:"Green" )switch view {case _ where view.height < 50 : print ("Shrter thant 50 units" ) case _ where view.width > 20 : print ("Over 50 tall, & over 20 wide" ) case _ where view.color = "Green" : print ("Over 50 tall, at most 20 wide, & green" ) default : print ("This view can't be described by this example" ) }
Programming exercises Fibonacci斐波那契数列 斐波那契数列每个数字都是前面两个数字之和例如0,1,1,2,3,5,8… 通过传入position的值,算出该位置的值。
1 2 3 4 5 6 7 8 9 10 func fibonacci (position : Int ) -> Int { switch position { case let n where n <= 1 : return 0 case 2 : return 1 case let n: return fiboncci(position: n - 1 ) + fibonacci(position: n- 2 ) } }
这个例子也是避免在Switch
中使用default
的例子,因为let n
已经包含所有的值,所以default
就不需要在写。
FizzBuzz 从1-100中,当是3的倍数的时候打印Fizz
,当是5的倍数的时候返回Buzz
,当既是5的倍数也是3的倍数的时候返回FizzBuzz
1 2 3 4 5 6 7 8 9 10 11 12 for i in 1 ... 100 { switch (i % 3 , i% 5 ) { case (0 , 0 ): print ("FizzBuzz" ) case (0 , _ ): print ("Fizz" ) case (_ , 0 ): print ("Buzz" ) case (_ , _ ): print (i) } }
Expression pattern 当你要检查Int的值是不是在一个范围内的时候,这时候就要用~=
符号来判断
1 2 3 4 5 let matched = (1...10 ~= 5) //true if case 1...10 = 5 { print("Int the range") }
Overloading~= 如果你要自己实现~=
例如,提供数组[0, 1, 2, 3]然后检查2是不是在该数组中,如果直接写以下代码会报错
1 2 3 4 5 6 7 8 9 10 let list = [0 , 1 , 2 , 3 ]let integer = 2 let isInArray = (list ~= integer) if case list = integer { print ("The integer is in the array" ) } else { print ("The integer is not in the array" ) }
重写~=方法
1 2 3 4 5 6 7 8 func ~= (pattern : [Int ], value : Int ) -> Bool { for i in pattern { if i == value { return true } } return false }