Files
knowledge-kit/Chapter1 - iOS/1.123.md
2024-04-27 13:01:58 +08:00

143 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Swift 模式匹配
## 模式匹配的底层实现
为了去除其他语句对汇编研究造成的干扰,所以 case 和 default 里面都很简单,聚焦于研究 case 的模式匹配实现。测试代码如下:
```swift
var age = 28
switch age {
case 0...30:
break
default:
break
}
```
`case 0...30:` 处加断点可以看到汇编,然后看到可疑方法 `Swift.RangeExpression.~= infix(τ_0_0, τ_0_0.Bound) -> Swift.Bool`
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/SwiftPatternMatchExplore.png" style="zoom:25%">
LLDB 输入 `si` 进去窥探下
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/SwiftPatternMatchExplore2.png" style="zoom:25%">
看样子,函数还没到底,看到地址 `0x00007ff81a86f530` 很大很大,猜测应该是一个系统动态库方法地址,继续跟进去研究 `si`
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/MemoryLayout.png)
可以看到内部还有函数调用
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/SwiftPatternMatchExplore3.png" style="zoom:25%">
继续跟进 `si`
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/SwiftPatternMatchExplore4.png" style="zoom:25%">
看上去是在做继续 `clasedRange` 区间符合的判断,继续跟进 `si`,里面确实是在判断是否命中区间的判断。不一一研究了,这次目的是判断 switch...case pattern 的实现。
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/SwiftPatternMatchExplore5.png" style="zoom:25%">
结论switch case pattern 模式匹配,系统底层实现是依赖
## 模式匹配的应用
自定义模式匹配。根据上面通过汇编进行分析,我们知道
- `static func ~=(pattern: case 后面的值, value: switch 后面的值)` pattern 代表的是 case 后面的值value 代表 switch 后面的值。
- 当 case 有不同类型的时候,如果编译报错,则需要重写 `static func ~=(pattern: ,value: )` 方法,调整 pattern 的数据类型,数据类型应该和 case 后的数据类型一致(可以是函数等)
```swift
struct Student {
var score = 0
var name = ""
/// Student Int
/// - Parameters:
/// - pattern: case
/// - value: switch
/// - Returns:
static func ~= (pattern: Int, value: Student) -> Bool {
value.score >= pattern
}
static func ~= (pattern: Range<Int>, value: Student) -> Bool {
pattern.contains(value.score)
}
static func ~= (pattern: ClosedRange<Int>, value: Student) -> Bool {
pattern.contains(value.score)
}
static func ~= (pattern: String, value: Student) -> Bool {
Int(pattern) == value.score
}
}
var student: Student = Student(score: 55, name: "杭城小刘")
switch student {
case 100:
print(">=100")
case 90:
print(">=90")
case 80..<90:
print("[80, 90)")
case 60...79:
print("[60, 79]")
case "55":
print("斯国一")
default:
print("just so so")
}
// console
```
修改 `var student: Student = Student(score: 78, name: "杭城小刘")` 则输出 `[60, 79]`
```swift
extension String {
static func ~=(pattern: (String) -> Bool ,value: String) -> Bool {
pattern(value)
}
}
func hasPrefix(_ prefix: String) -> (String) -> Bool {
{$0.hasPrefix(prefix)}
}
func hasSuffix(_ prefix: String) -> (String) -> Bool {
{$0.hasSuffix(prefix)}
}
var name = "城小刘"
switch name {
case hasPrefix(""):
print("有杭哦")
case hasSuffix(""):
print("有刘哦")
default:
print("just a name")
}
// console
```
##