docs: clang 插件开发

This commit is contained in:
杭城小刘
2024-04-27 13:01:58 +08:00
parent 6e47061735
commit 851797d133
257 changed files with 9060 additions and 239 deletions

266
Chapter1 - iOS/1.117.md Normal file
View File

@@ -0,0 +1,266 @@
# Swift 协议探究
- 协议可以用来定义属性、方法、下标的声明,协议可以被类、枚举、结构体遵守(多个协议用逗号隔开)
- 协议中定义的方法不能有默认参数值
- 协议中定义属性必须是 `var`
- 实现协议时定义的属性权限,要不小于协议中定义的属性权限
- 协议定义属性是 `get``set` 时,用 `var` 存储属性或者 `get``set` 计算属性实现
- 为了保证通用,协议中必须用 `static` 定义类型方法、类型属性、类型下标
- 只有将协议中的实例方法标记为 `mutating`
- 才可以允许结构体、枚举对象在方法里修改自身内存。否则编译器会报错:`Cannot assign to property: 'self' is immutable`
- 类遵循协议,实现方法的时候不用加 `mutating`,枚举、结构体的实现需要加 `mutating`
```swift
protocol Drawable {
func draw()
}
class Size: Drawable {
var width: Int = 0
func draw() {
width = 10
}
}
var size = Size()
print(size.width) // 0
size.draw()
print(size.width) // 10
struct Point: Drawable {
var x : Int = 0
var y: Int = 0
func draw() {
x = 10 // Cannot assign to property: 'self' is immutable
y = 10 // Cannot assign to property: 'self' is immutable
}
}
```
要想修改需要加 `mumating`
```swift
struct Point: Drawable {
var x : Int = 0
var y: Int = 0
mutating func draw() {
x = 10
y = 10
}
}
var point = Point()
print(point.x, point.y)
point.draw()
print(point.x, point.y)
```
- 协议中还可以定义初始化器 `init`,非 `final` 类实现协议时, `init` 方法必须加 `required`
```swift
protocol Drawable {
init(x: Int, y: Int)
}
class Point: Drawable {
var x: Int = 0
var y: Int = 0
required init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
final class Size: Drawable {
var x: Int = 0
var y: Int = 0
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
var point = Point(x: 10, y: 20)
print(point.x , point.y) // 10 20
var size = Size(x: 30, y: 40)
print(size.x , size.y) // 30 40
```
- 如果协议声明了初始化器,某个类遵循协议并实现了初始化器。且该初始化器也恰好是父类指定初始化器,那么这个初始化必须同事加 `required` 和 `override`
```swift
protocol Drawable {
init(x: Int, y: Int)
}
class Shape {
init(x: Int, y: Int) {}
}
class Circle: Shape, Drawable {
var x: Int = 0
var y: Int = 0
required override init(x: Int, y: Int) {
super.init(x: x, y: y)
self.x = x
self.y = y
}
}
var circle = Circle(x: 10, y: 20)
print(circle.x , circle.y) // 10 20
```
- 协议也可以继承
- 协议也可以组合
```swift
protocol Drawable {}
protocol Colorable {}
func test1(obj: Shape) {} // 参数接收 Shape 类或者 Shape 类的子类
func test2(obj: Drawable) {} // 参数接收遵循 Drawable 的实例
func test3(obj: Drawable & Colorable) {} // 参数接收同时遵循 Colorable 和 Drawable 2个协议的实例
func test4(obj: Shape & Drawable & Colorable) {} // 参数接收同时遵循 Colorable 和 Drawable 2个协议且是 Shape 的子类的实例
```
- 遵循 `CustomStringConvertible` 可以自定义打印的字符串内容
```swift
class Person: CustomStringConvertible {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
var description: String {
"My name is \(name), age is \(age)"
}
}
var p = Person(name: "杭城小刘", age: 28)
print(p) // My name is 杭城小刘, age is 28
```
## Any、AnyObject
Swift 提供了2种特殊的类型Any、AnyObject
- Any 可以代表任意类型(枚举、结构体、类、函数类型)
- AnyObject代表任意类类型。比如可以在协议后面加上 AnyObject 则代表只有类能遵循这个协议。编译器会做检查 `Non-class type 'point' cannot conform to class protocol 'Eatable'`
```swift
protocol Eatable: AnyObject {}
class Person: Eatable { }
struct point: Eatable {} // Non-class type 'point' cannot conform to class protocol 'Eatable'
```
## 关联类型
关联类型的作用:给协议中用到的类型,定义一个占位名称
协议中可以拥有多个关联类型
```swift
protocol Stackable {
associatedtype Element
mutating func push(_ element: Element)
mutating func pop() -> Element
func top() -> Element
func size() -> Int
}
class Stack<Element>: Stackable {
var elements = Array<Element>()
func push(_ element: Element) {
elements.append(element)
}
func pop() -> Element {
elements.removeLast()
}
func top() -> Element {
elements.last!
}
func size() -> Int {
elements.count
}
}
```
## Swift 范型本质
```swift
func swapValue<T>(_ value1: inout T, _ value2: inout T) {
(value1, value2) = (value2, value1)
}
var i1 = 11
var i2 = 22
swapValue(&i1, &i2)
var s1 = "Hello"
var s2 = "world"
swapValue(&s1, &s2)
```
在 `swapValue(&i1, &i2)` 处下断点可以看到下面的汇编代码:
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/SwiftGenericExploreDemo1.png" style="zoom:25%">
可以看到:
- 在第一处调用 `swapValue ` 方法的时候将8字节的 metadata 信息保存到 `rdx` 寄存器了。也就是在调用 `swapValue` 方法的时候,分别将 `i1`0x000000000000000b也就是11的地址值赋值给 rdi 寄存器,将 `i2`0x0000000000000016也就是22的地址值赋值给 rsi 寄存器
- 将 `Int` 的 `metadata` 赋值给 `rdx` 寄存器
- 然后调用 `swapValue` 方法
- 后续的 `String` 的 `SwapValue` 过程类似
所以编译器最后在执行的时候,会将范型真正的类型对应的 metadata 信息当作函数参数,传递进去,再去执行函数
## 范型类型约束
范型必须遵循协议,可以在方法后加 `<>`,在 `<>` 内写范型 `T: 需要继承的类 & 协议` (也可以是其他名字,大多数语言都写 T
```swift
protocol Runable {}
class Person {}
func swapValue<T: Person & Runable>(_ a: inout T, _ b: inout T) {
(a, b) = (b, a)
}
```
另一种场景是在方法参数是某个范型且遵循协议后,对其范型有更多限制,则用 `where` 去处理。如下例子
```swift
protocol Stackable {
associatedtype Element: Equatable
}
class Stack<E: Equatable>: Stackable {
typealias Element = E
}
func equal<S1: Stackable, S2: Stackable>(_ s1: S1, _ s2: S2)-> Bool
where S1.Element == S2.Element, S1.Element: Hashable {
return true
}
let s1 = Stack<Int>()
let s2 = Stack<Int>()
let s3 = Stack<String>()
var result:Bool = equal(s1, s2)
print(result) // true
result = equal(s1, s3) // Global function 'equal' requires the types 'Stack<Int>.Element' (aka 'Int') and 'Stack<String>.Element' (aka 'String') be equivalent
print(result)
```