mirror of
https://github.com/NohamR/knowledge-kit.git
synced 2026-05-25 12:27:15 +00:00
143 lines
3.7 KiB
Markdown
143 lines
3.7 KiB
Markdown
# 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`
|
||
|
||
|
||
|
||

|
||
|
||
可以看到内部还有函数调用
|
||
|
||
<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
|
||
有刘哦
|
||
```
|
||
|
||
|
||
|
||
##
|
||
|
||
|
||
|