Swift第十章 字面量、模式匹配

字面量(Literal)

  1. 下面代码中的10、false、”Jack”就是字面量

     var age = 10
     var isRed = false
     var name = "Jack"
     //这些字面量默认会是什么类型呢?
    
  2. 常见字面量的默认类型,标准库定义

     //整型字面量类型等于Int
     public typealias IntegerLiteralType = Int
     public typealias FloatLiteralType = Double
     public typealias BooleanLiteralType = Bool
     public typealias StringLiteralType = String
    
  3. 可以通过typealias修改字面量的默认类型

     typealias FloatLiteralType = Float
     typealias IntegerLiteralType = UInt8
     var age = 10 // UInt8
     var height = 1.68 // Float
    
  4. Swift自带的绝大部分类型,都支持直接通过字面量进行初始化

    1. Bool、Int、Float、Double、String、Array、Dictionary、Set、Optional等

### 字面量协议

  1. Swift自带类型之所以能够通过字面量初始化,是因为它们遵守了对应的协议

    Bool : ExpressibleByBooleanLiteral
    Int : ExpressibleByIntegerLiteral
    Float、Double : ExpressibleByIntegerLiteral、xpressibleByFloatLiteral
    Dictionary : ExpressibleByDictionaryLiteral
    String : ExpressibleByStringLiteral
    Array、Set : ExpressibleByArrayLiteral
    Optional : ExpressibleByNilLiteral var b: Bool = false // ExpressibleByBooleanLiteral
    
  2. 举例

     var i: Int = 10 // ExpressibleByIntegerLiteral
     var f0: Float = 10 // ExpressibleByIntegerLiteral
     var f1: Float = 10.0 // ExpressibleByFloatLiteral
     var d0: Double = 10 // ExpressibleByIntegerLiteral
     var d1: Double = 10.0 // ExpressibleByFloatLiteral
     var s: String = "jack" // ExpressibleByStringLiteral
     var arr: Array = [1, 2, 3] // ExpressibleByArrayLiteral
     var set: Set = [1, 2, 3] // ExpressibleByArrayLiteral
     var dict: Dictionary = ["jack" : 60] // ExpressibleByDictionaryLiteral
     var o: Optional<Int> = nil // ExpressibleByNilLiteral
    
  3. 字面量协议应用

     extension Int : ExpressibleByBooleanLiteral {
         public init(booleanLiteral value: Bool) { self = value ? 1 : 0 }
     }
     var num: Int = true
     print(num) // 1
        
     class Student : ExpressibleByIntegerLiteral, ExpressibleByFloatLiteral, ExpressibleByStringLiteral, 
     CustomStringConvertible {
         var name: String = ""
         var score: Double = 0
         required init(floatLiteral value: Double) { self.score = value }
         required init(integerLiteral value: Int) { self.score = Double(value) }
         required init(stringLiteral value: String) { self.name = value }
         required init(unicodeScalarLiteral value: String) { self.name = value }
         required init(extendedGraphemeClusterLiteral value: String) { self.name = value }
         var description: String { "name=\(name),score=\(score)" }
     }
        
     var stu: Student = 90
     print(stu) // name=,score=90.0
     stu = 98.5
     print(stu) // name=,score=98.5
     stu = "Jack"
     print(stu) // name=Jack,score=0.0
        
     struct Point {
         var x = 0.0, y = 0.0
     }
     extension Point : ExpressibleByArrayLiteral, ExpressibleByDictionaryLiteral {
         init(arrayLiteral elements: Double...) {
             guard elements.count > 0 else { return }
             self.x = elements[0]
             guard elements.count > 1 else { return }
             self.y = elements[1]
         }
         init(dictionaryLiteral elements: (String, Double)...) {
             for (k, v) in elements {
                 if k == "x" { self.x = v }
                 else if k == "y" { self.y = v }
             }
         }
     }
     var p: Point = [10.5, 20.5]
     print(p) // Point(x: 10.5, y: 20.5)
     p = ["x" : 11, "y" : 22]
     print(p) // Point(x: 11.0, y: 22.0)
    

模式匹配

模式(Pattern)

  1. 什么是模式?模式是用于匹配的规则,比如switch的case、捕捉错误的catch、if\guard\while\for语句的条件等
  2. Swift中的模式有
    1. 通配符模式(Wildcard Pattern)
    2. 标识符模式(Identifier Pattern)
    3. 值绑定模式(Value-Binding Pattern)
    4. 元组模式(Tuple Pattern)
    5. 枚举Case模式(Enumeration Case Pattern)
    6. 可选模式(Optional Pattern)
    7. 类型转换模式(Type-Casting Pattern)
    8. 表达式模式(Expression Pattern)

通配符模式(Wildcard Pattern)

  1. _ 匹配任何值
  2. _? 匹配非nil值

     enum Life {
         case human(name: String, age: Int?)
         case animal(name: String, age: Int?)
     }
     func check(_ life: Life) {
         switch life {
             //age是任何职都可以匹配
             case .human(let name, _):
                 print("human", name)
             //age是非nil值可以匹配
             case .animal(let name, _?):
                 print("animal", name)
             default:
                 print("other")
         }
     }
        
     check(.human(name: "Rose", age: 20)) // human Rose
     check(.human(name: "Jack", age: nil)) // human Jack
     check(.animal(name: "Dog", age: 5)) // animal Dog
     check(.animal(name: "Cat", age: nil)) // other
    

标识符模式(Identifier Pattern)

  1. 给对应的变量、常量名赋值

     var age = 10
     let name = "jack"
    

值绑定模式(Value-Binding Pattern)

```
let point = (3, 2)
switch point {
    //x=3,y= 2
    case let (x, y):
    print("The point is at (\(x), \(y)).")
}
```

元组模式(Tuple Pattern)

let points = [(0, 0), (1, 0), (2, 0)]
//只匹配每个元祖元素的x值
for (x, _) in points {
    print(x)
}

let name: String? = "jack"
let age = 18
let info: Any = [1, 2]
switch (name, age, info) {
case (_?, _ , _ as String):
    print("case")
default:
    print("default")
} // default

var scores = ["jack" : 98, "rose" : 100, "kate" : 86]
for (name, score) in scores {
    print(name, score)
}

枚举Case模式(Enumeration Case Pattern)

  1. if case语句等价于只有1个case的switch语句

     let age = 2
     // 原来的写法
     if age >= 0 && age <= 9 {
         print("[0, 9]")
     }
     // 枚举Case模式,这里的=是匹配意思
     if case 0...9 = age {
         print("[0, 9]")
     }
     guard case 0...9 = age else { return }
     print("[0, 9]")
        
     //等价于上面的if case
     switch age {
         case 0...9: print("[0, 9]")
         default: break
     }
        
     //for case
     let ages: [Int?] = [2, 3, nil, 5]
     //拿到数组中的每一额元素与nil匹配
     for case nil in ages {
         print("有nil值")
         break
     } // 有nil值
        
     let points = [(1, 0), (2, 1), (3, 0)]
     //取出每一个元祖元素,y值必须为0的值才能匹配上
     for case let (x, 0) in points {
         print(x)
     } // 1 3
    

可选模式(Optional Pattern)

let age: Int? = 42
//x? 等价于 .some
if case .some(let x) = age { print(x) }
//将age与if case进行匹配,x?表示age为非空才能匹配成功,然后将age进行解包赋值给x
if case let x? = age { print(x) }


let ages: [Int?] = [nil, 2, 3, nil, 5]
//取出ages中的每一个值与for case进行匹配,只有非空值才能匹配成功,然后将元素进行解包赋值给age
for case let age? in ages {
    print(age)
} // 2 3 5

let ages: [Int?] = [nil, 2, 3, nil, 5]
for item in ages {
    if let age = item {
        print(age)
    }
} // 跟上面的for,效果是等价的

//Int?传参必须是非空
func check(_ num: Int?) {
    switch num {
        case 2?: print("2")
        case 4?: print("4")
        case 6?: print("6")
        case _?: print("other")
        case _: print("nil")
    }
}
check(4) // 4
check(8) // other
check(nil) // nil

类型转换模式(Type-Casting Pattern)

  1. case中的is是判断,as是强制转换
let num: Any = 6
switch num {
case is Int:
    // 编译器依然认为num是Any类型
    print("is Int", num)
//case let n as Int:  
    //此时的n被强制转换为Int类型
    // print("as Int", n + 1)
default:
    break
}

class Animal { func eat() { print(type(of: self), "eat") } }
class Dog : Animal { func run() { print(type(of: self), "run") } }
class Cat : Animal { func jump() { print(type(of: self), "jump") } }
func check(_ animal: Animal) {
    switch animal {
    case let dog as Dog:
        dog.eat()
        dog.run()
    case is Cat:
        animal.eat()
    default: break
    }
}
// Dog eat
// Dog run
check(Dog())
// Cat eat
check(Cat())

表达式模式(Expression Pattern)

  1. 表达式模式用在case中

     let point = (1, 2)
     switch point {
     //元祖的xy都是0才能匹配上
     case (0, 0):
         print("(0, 0) is at the origin.")
     //元组的取值范围在-2,2,y的取值范围在-2,2
     case (-2...2, -2...2):
         print("(\(point.0), \(point.1)) is near the origin.")
     default:
         print("The point is at (\(point.0), \(point.1)).")
     } // (1, 2) is near the origin.
    

自定义表达式模式

  1. 通过汇编得知,swift的case匹配本质是调用了“~=”运算符,那么可以通过重载运算符“~=”,自定义表达式模式的匹配规则
  2. 示例1:

     struct Student {
         var score = 0, name = ""
         //重载~=运算符
         //返回值固定为Bool,参数:pattern表示case后面的表达式,value表示当前类型,也是switch后面的放的实例类型
         static func ~= (pattern: Int, value: Student) -> Bool { 
             value.score >= pattern 
         }
            
         static func ~= (pattern: ClosedRange<Int>, value: Student) -> Bool { 
             pattern.contains(value.score) 
         }
         static func ~= (pattern: Range<Int>, value: Student) -> Bool { 
             pattern.contains(value.score) 
         }
     }
        
     //使用
     var stu = Student(score: 75, name: "Jack")
     switch stu {
         case 100: print(">= 100")
         case 90: print(">= 90")
         case 80..<90: print("[80, 90)")
         case 60...79: print("[60, 79]")
         case 0: print(">= 0")
         default: break
     } // [60, 79]
        
     //只有一个case的switch case,等价于switch stu {
         case 60: print(">= 100");default: break;}
     if case 60 = stu {
         print(">= 60")
     } // >= 60
        
     var info = (Student(score: 70, name: "Jack"), "及格")
     switch info {
         //info元组中的Student实例跟60进行匹配,后面字符串跟test进行匹配
         case let (60, text): print(text)
         default: break
     } // 及格
    
  3. 实例2:

     extension String {
         //pattern是case后面的东西,value是switch后面的东西
         static func ~= (pattern: (String) -> Bool, value: String) -> Bool {
             pattern(value)
         }
     }
     func hasPrefix(_ prefix: String) -> ((String) -> Bool) { 
         return {
             (str:String) -> Bool in
             str.hasPrefix(prefix)
         }
         //缩写如下,$0代表最前面参数
         //{ $0.hasPrefix(prefix) } 
     }
     func hasSuffix(_ suffix: String) -> ((String) -> Bool) { { $0.hasSuffix(suffix) } }
        
     //使用
     var str = "jack"
     switch str {
     //hasPrefix("j")返回结果是一个函数类型((String) -> Bool
     case hasPrefix("j"), hasSuffix("k"):
         print("以j开头,以k结尾")
     default: break
     } // 以j开头,以k结尾
    
  4. 实例3:

     //偶数
     func isEven(_ i: Int) -> Bool { i % 2 == 0 }
     //奇数
     func isOdd(_ i: Int) -> Bool { i % 2 != 0 }
        
     extension Int {
         //pattern是case后面的东西,value是switch后面的东西
         static func ~= (pattern: (Int) -> Bool, value: Int) -> Bool {
             pattern(value)
         }
     }
     //使用
     var age = 9
     switch age {
         case isEven:
             print("偶数")
         case isOdd:
             print("奇数")
         default:
             print("其他")
     }
        
     prefix operator ~>
     prefix operator ~>=
     prefix operator ~<
     prefix operator ~<=
     prefix func ~> (_ i: Int) -> ((Int) -> Bool) { { $0 > i } }
     prefix func ~>= (_ i: Int) -> ((Int) -> Bool) { { $0 >= i } }
     prefix func ~< (_ i: Int) -> ((Int) -> Bool) { { $0 < i } }
     prefix func ~<= (_ i: Int) -> ((Int) -> Bool) { { $0 <= i } }
        
     var age = 9
     switch age {
         case ~>=0:
             print("1")
         case ~>10:
             print("2")
         default: break
     } // [0, 10]
    

where

  1. 可以使用where为模式匹配增加匹配条件

     //where用在case上
     var data = (10, "Jack")
     switch data {
     case let (age, _) where age > 10:
         print(data.1, "age>10")
     case let (age, _) where age > 0:
         print(data.1, "age>0")
     default: break
     }
     //用在cor循环上
     var ages = [10, 20, 44, 23, 55]
     for age in ages where age > 30 {
         print(age)
     } // 44 55
        
     //用在协议
     protocol Stackable { associatedtype Element }
     protocol Container {
         associatedtype Stack : Stackable where Stack.Element : Equatable
     }
        
     func equal<S1: Stackable, S2: Stackable>(_ s1: S1, _ s2: S2) -> Bool
         where S1.Element == S2.Element, S1.Element : Hashable {
         return false
     }
     //用在扩展
     extension Container where Self.Stack.Element : Hashable { }
    
Table of Contents