一、字面量
- 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、什么是模式?
- 模式是用于匹配的规则,比如
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)
- 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
语句等价于只有1
个case
的switch
语句
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") }
枚举就只有:
none
和some
- 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 { }