Swift5.0 - day9-字面量协议、模式匹配

简介: 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 { }


目录
相关文章
|
3月前
|
Swift iOS开发
Swift 语言: 什么是协议(Protocol)?如何实现和使用协议?
Swift 语言: 什么是协议(Protocol)?如何实现和使用协议?
41 2
|
6月前
|
算法 Swift C++
34 Swift为了协议 关联类型
Swift为了协议 关联类型
38 0
|
6月前
|
存储 Swift iOS开发
31 Swift 继续聊聊协议扩展
Swift 继续聊聊协议扩展
49 0
|
6月前
|
测试技术 Swift
17 Swift中的模式和模式匹配
Swift中的模式和模式匹配
81 2
|
6月前
|
Swift C++ Ruby
32 Swift面向协议编程初探
32 Swift面向协议编程初探
37 0
|
存储 前端开发 Swift
Swift实用小册20: Protocol协议的使用
在本章中,你将学会Protocol协议的使用方法。
218 0
Swift实用小册20: Protocol协议的使用
|
Swift iOS开发
Swift:暗黑模式iOS 13以上支持是否跟随系统和iOS13以下的主题适配
Swift:暗黑模式iOS 13以上支持是否跟随系统和iOS13以下的主题适配
1267 0
Swift:暗黑模式iOS 13以上支持是否跟随系统和iOS13以下的主题适配
|
Swift C++ 开发者
Swift5.0 - day12 - 面向协议编程
Swift5.0 - day12 - 面向协议编程
279 0
|
存储 Swift
Swift5.0 - day5-继承、初始化、可选链、协议(下)
Swift5.0 - day5-继承、初始化、可选链、协议(下)
78 0
|
存储 安全 Java
Swift5.0 - day5-继承、初始化、可选链、协议(上)
Swift5.0 - day5-继承、初始化、可选链、协议(上)
101 0
Swift5.0 - day5-继承、初始化、可选链、协议(上)

相关课程

更多