Swift5.0 - day9-字面量協議、模式匹配

一、字面量

  • 1.1、常見字面量的默認類型

    public typealias IntegerLiteralType = Int 
    public typealias FloatLiteralType = Double 
    public typealias BooleanLiteralType = Bool 
    public typealias StringLiteralType = String
    
    • 舉例,下面代碼中的10、false、"Jack" 就是字面量

      var age = 10
      var isRed = false
      var name = "Jack"
      
    • 可以通過typealias修改字面量的默認類型,建議不要修改

      typealias FloatLiteralType = Float 
      typealias IntegerLiteralType = UInt8 
      var age = 10 // UInt8
      var height = 1.68 // Float
      
    • Swift自帶的絕大部分類型,都支持直接通過字面量進行初始化,如:Bool、Int、Float、Double、String、Array、Dictionary、Set、Optional

  • 1.2、字面量協議, Swift自帶類型之所以能夠通過字面量初始化,是因為它們遵守了對應的協議

    Bool : ExpressibleByBooleanLiteral
    Int : ExpressibleByIntegerLiteral
    Float、Double : ExpressibleByIntegerLiteral、ExpressibleByFloatLiteral 
    Dictionary : ExpressibleByDictionaryLiteral
    String : ExpressibleByStringLiteral
    Array、Set : ExpressibleByArrayLiteral 
    Optional : ExpressibleByNilLiteral
    

    左邊類型,右邊協議

    var b: Bool = false // ExpressibleByBooleanLiteral
    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
    
  • 1.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
    stu = 98.5
    print(stu) // name=,score=98.5 stu = "Jack"
    stu = "Jack"
    print(stu) // name=Jack,score=0.0
    
  • 1.4、字面量協議應用二

    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)
    

二、模式匹配

  • 2.1、什么是模式?

    • 模式是用于匹配的規則,比如 switchcase、捕捉錯誤的catch、if\guard\while\for語句的條件等
    • Swift中的模式有
      • 通配符模式(Wildcard Pattern)
      • 標識符模式(Identifier Pattern)
      • 值綁定模式(Value-Binding Pattern)
      • 元組模式(Tuple Pattern)
      • 枚舉Case模式(Enumeration Case Pattern)
      • 可選模式(Optional Pattern)
      • 類型轉換模式(Type-Casting Pattern)
      • 表達式模式(Expression Pattern)
  • 2.2、通配符模式(Wildcard Pattern)
    _ 匹配任何值
    _? 匹配非nil值

    enum Life {
        case human(name: String, age: Int?)
        case animal(name: String, age: Int?)
    }
    
    func check(_ life: Life) {
        switch life {
        case .human(let name, _):
            print("human", name)
        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
    

    提示:平時遇到的 值?一般都表示非nil

    var num: Int? = 10
    switch num {
    case let v?:
          print(v)
    case nil:
          print("nil")
    }
    
  • 2.3、標識符模式(Identifier Pattern)
    給對一個的常量、變量名賦值

    var age = 10
    let name = "Jack"
    
  • 2.4、值綁定模式(Value-Binding Pattern)

    let point = (3, 2)
    switch point {
    case let (x, y):
        print("The point is at (\(x), \(y)).")
    }
    
  • 2.5、元組模式(Tuple Pattern)

    let points = [(0, 0), (1, 0), (2, 0)]
    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 = ["joan" : 8,"jack" : 98, "rose" : 100, "kate" : 86]
    for (name, score) in scores {
        print(name, score)
    }
    
  • 2.6、枚舉Case模式(Enumeration Case Pattern)
    if case 語句等價于只有 1caseswitch 語句

    let age = 2
    // 原來的寫法
    if age >= 0 && age <= 9 {
         print("[0, 9]")
    }
    // 枚舉Case模式
    if case 0...9 = age {
         print("[0, 9]")
    }
    
    func test() {
         guard case 0...9 = age else {
             print("不在此范圍")
             return
         }
         print("[0, 9]")
    }
    
    test()
    
    switch age {
    case 0...9: print("[0, 9]")
    default: break
    }
    
    let ages: [Int?] = [2, 3, nil, 5]
    for case nil in ages {
       print("有nil值")
       break
    }
    
    let points = [(1, 0), (2, 1), (3, 0)]
    for case let (x, 0) in points {
        print(x)
    } // 1 3
    
  • 2.7、可選模式(Optional Pattern)

    • 不為 nil

      let age: Int? = 42
      if case .some(let x) = age { print(x) }
      if case let x? = age { print(x) }
      
    • 匹配 case let age? in ages 中的 age? 不為 nil

      let ages: [Int?] = [nil, 2, 3, nil, 5]
      for case let age? in ages {
           // 2 3 5
           print(age)
      }
      

      提示:上面的代碼等價于下面的

      let ages1: [Int?] = [nil, 2, 3, nil, 5]
      for item in ages1 {
           if let age = item {
                print(age)
           }
      }
      
    • 多個case匹配

      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
      

      提示:2? 代表值不為nil,值為 2;_?代表值不為nil,什么值都可以;_ 代表任何值都可以

    • 下面兩段代碼等效

      var age: Int? = 10
      
      switch age {
      case let x?:
          print(x)
      case nil:
          print("nil")
      }
      
      switch age {
      case .some(let x):
          print(x)
      case .none:
          print("nil")
      }
      

      枚舉就只有:nonesome

  • 2.8、類型轉換模式(Type-Casting Pattern)

    let num: Any = 6
    switch num {
    case is Int:
       // 編譯器依然認為num是Any類型
       print("is Int", num)
       // case let n as Int:
       // print("as Int", n + 1)
    default:
       break
    }
    

    提示:case is Int 是在匹配 num 是不是 Int 類型

    • case let n as Int:在匹配的時候 num 還是Any 類型,但是 n 是 Int 類型
    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())
    

    重點指出的是:check(Cat()) 在執行的時候,case is Cat:里面調用的是 animal.eat(),打印的是 Cat eat,那是因為 type(of: self) 可以識別是誰在真的調用,在case is Cat:里面是只能調用 Animal類里面的方法的

  • 2.9、表達式模式(Expression Pattern)

    • 表達式模式用在 case 中

      let point = (1, 2)
      switch point {
      case (0, 0):
         print("(0, 0) is at the origin.")
      case (-2...2, -2...2):
         print("(\(point.0), \(point.1)) is near the origin.")
      default:
         // (1, 2) is near the origin.
         print("The point is at (\(point.0), \(point.1)).") } 
      
    • 自定義表達式模式 1 :可以通過重載運算符,自定義表達式模式的匹配規則,比較復雜的switch 是調用 ~=運算符

      struct Student {
          var score = 0, name = ""
          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]")  // [60, 79]
      case 0: print(">= 0")
      default: break
      }
      

      在重載 ~= 運算符的時候,有些格式是固定的,如:static func ~= (pattern: Int, value: Student) -> Bool:pattern 是case后面放的東西,value 是 switch 里面放的東西,返回值 Bool 是固定的

      if case 60 = stu {
          print(">= 60") // >= 60
      }
      
      var info = (Student(score: 70, name: "Jack"), "及格")
      switch info {
      case let (60, text):
          print(text)  // 及格
      default: break
      }
      
    • 自定義表達式模式 2 :匹配字符串 前綴后綴 的模式

      extension String {
          static func ~= (pattern: (String) -> Bool, value: String) -> Bool {
               pattern(value)
          }
      }
      
      func hasPrefix(_ prefix: String) -> ((String) -> Bool) { { $0.hasPrefix(prefix) } }
      func hasSuffix(_ suffix: String) -> ((String) -> Bool) { { $0.hasSuffix(suffix) } }
      
      var str = "jack"
      switch str {
      case hasPrefix("j"), hasSuffix("k"):
         print("以j開頭,以k結尾")
      default: break
      }
      

      提示:hasPrefix 后面的 { { $0.hasPrefix(prefix) } } 是簡寫,全部代碼如下,同樣

      func hasPrefix(_ prefix: String) -> ((String) -> Bool) { 
             return { 
                     (str: String) -> Bool in
                     str.hasPrefix(prefix) 
             } 
      }
      
    • 自定義表達式模式 3 :奇數和偶數的判斷

      func isEven(_ i: Int) -> Bool { i % 2 == 0 }
      func isOdd(_ i: Int) -> Bool { i % 2 != 0 }
      extension Int {
          static func ~= (pattern: (Int) -> Bool, value: Int) -> Bool {
              pattern(value)
          }
      }
      var age = 9
      switch age {
      case isEven:
         print("偶數")
      case isOdd:
         print("奇數")
      default:
         print("其他")
      }
      
    • 自定義表達式模式 4 :自定義符號,下面是前置運算符

      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 } }
      
      extension Int {
          static func ~= (pattern: (Int) -> Bool, value: Int) -> Bool {
             pattern(value)
          }
      }
      
      var age = 9
      switch age {
      case ~>=0:
          print("1")
      case ~>10:
          print("2")
      default: break
      } 
      
  • 2.10、可以使用 where 為模式匹配增加匹配條件

    • (1)、 switch 里面使用

      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
      }
      
    • (2)、 for in 里面使用

      var ages = [10, 20, 44, 23, 55]
      for age in ages where age > 30 {
          print(age) // 44 55
      } 
      
    • (3)、 協議中關聯類型里面使用

      protocol Stackable { associatedtype Element }
      protocol Container {
          associatedtype Stack : Stackable where Stack.Element : Equatable
      }
      
    • (4)、 函數里面使用

      func equal<S1: Stackable, S2: Stackable>(_ s1: S1, _ s2: S2) -> Bool where S1.Element == S2.Element, S1.Element : Hashable {
         return false
      }
      
    • (5)、 擴展里面使用

       extension Container where Self.Stack.Element : Hashable { }
      
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,570評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,786評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,219評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,438評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,971評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,796評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,995評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,230評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,697評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容