Swift第十章 字面量、模式匹配
字面量(Literal)
-
下面代码中的10、false、”Jack”就是字面量
var age = 10 var isRed = false var name = "Jack" //这些字面量默认会是什么类型呢? -
常见字面量的默认类型,标准库定义
//整型字面量类型等于Int public typealias IntegerLiteralType = Int public typealias FloatLiteralType = Double public typealias BooleanLiteralType = Bool public typealias StringLiteralType = String -
可以通过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等
### 字面量协议
-
Swift自带类型之所以能够通过字面量初始化,是因为它们遵守了对应的协议
Bool : ExpressibleByBooleanLiteral Int : ExpressibleByIntegerLiteral Float、Double : ExpressibleByIntegerLiteral、xpressibleByFloatLiteral 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 -
字面量协议应用
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)
- 什么是模式?模式是用于匹配的规则,比如switch的case、捕捉错误的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)
通配符模式(Wildcard Pattern)
- _ 匹配任何值
-
_? 匹配非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)
-
给对应的变量、常量名赋值
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)
-
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)
- 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)
-
表达式模式用在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.
自定义表达式模式
- 通过汇编得知,swift的case匹配本质是调用了“~=”运算符,那么可以通过重载运算符“~=”,自定义表达式模式的匹配规则
-
示例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 } // 及格 -
实例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结尾 -
实例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
-
可以使用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 { }