Swift 是一个强类型的语言,它通过协议(Protocol)为类型提供功能扩展的强大能力。本篇文章将深入解析四个在开发中非常常见也非常重要的协议:Equatable、Hashable、Identifiable 和 Comparable。掌握它们不仅可以写出更简洁、更强大的代码,也能够更好地与 Swift 标准库(如数组、集合、字典等)进行交互。
Equatable 协议
什么是 Equatable?
Equatable 是 Swift 中用于判断**两个值是否"相等"**的协议。只要一个类型遵循了 Equatable,你就可以使用 == 和 != 运算符来比较两个该类型的实例是否相等。
Swift 中大多数内建类型(如 Int、String、Double、Array、Dictionary 等)都已经默认实现了 Equatable。
语法定义
            
            
              swift
              
              
            
          
          protocol Equatable {
    static func == (lhs: Self, rhs: Self) -> Bool
}
        这表示:你需要实现一个静态函数 ==,接收两个同类型的参数,返回它们是否相等的布尔值。
使用场景
- 比较两个结构体或枚举是否"内容一致"
 - 在集合操作中使用,如 
contains()、firstIndex(of:) - 用于控制流中,如 
if x == y { ... } - 搭配 
Hashable自动派生哈希值逻辑 
自动合成 ==
当你的结构体中所有属性都遵循 Equatable 时,Swift 会自动为你合成 == 运算符的实现,不需要手动写。
            
            
              swift
              
              
            
          
          struct Person: Equatable {
    let name: String
    let age: Int
}
// 编译器合成逻辑相当于:
/*
static func == (lhs: Person, rhs: Person) -> Bool {
    return lhs.name == rhs.name && lhs.age == rhs.age
}
*/
let p1 = Person(name: "Alice", age: 25)
let p2 = Person(name: "Alice", age: 25)
let p3 = Person(name: "Bob", age: 30)
print(p1 == p2)  // true
print(p1 == p3)  // false
        手动实现 ==(部分属性比较)
有时候你不想比较所有属性,只关注关键字段,这种情况下可以自定义 == 实现。
            
            
              swift
              
              
            
          
          struct Book: Equatable {
    let title: String
    let author: String
    let isbn: String
    // 只比较 ISBN,忽略作者和书名
    static func == (lhs: Book, rhs: Book) -> Bool {
        return lhs.isbn == rhs.isbn
    }
}
        这对某些实际场景非常有用,比如比较唯一标识符是否一致、或者忽略元数据差异。
注意事项
| 规则 | 是否自动合成 | 
|---|---|
所有属性都遵守 Equatable | 
✅ 是 | 
有任意一个属性不符合 Equatable | 
❌ 否 | 
已自定义 == 实现 | 
❌ 编译器不会再自动合成 | 
引用类型 class 默认不合成 ==(需手动) | 
❌ 否 | 
与引用类型区别
对于 class(引用类型):
==不会自动合成,即使所有属性都符合Equatable;- 默认比较的是内存地址是否相同 (使用 
===); - 如果你希望比较内容一致性,必须手动实现 
Equatable。 
Hashable 协议
什么是 Hashable?
Hashable 协议允许你的类型用于集合类型如 Set,或作为 Dictionary 的键(key)。它要求类型能够生成一个哈希值,供底层哈希表结构判断元素存储位置与是否相等。
当一个类型遵循 Hashable,它也必须遵循 Equatable,因为哈希值相同的两个对象,还需通过 == 判断是否真的"相等"。
语法定义
            
            
              swift
              
              
            
          
          protocol Hashable: Equatable {
    func hash(into hasher: inout Hasher)
}
        使用场景
• Set 中的元素类型 Element 必须是 Hashable
• Dictionary<Key, Value> 中的 Key 类型必须是 Hashable
• 快速查找/去重(基于哈希表)
自动合成 Hashable
当一个结构体中所有属性本身都是 Hashable 类型时,Swift 会自动合成 hash(into:) 和 ==。
            
            
              swift
              
              
            
          
          struct User: Hashable {
    let id: Int
    let username: String
}
var users: Set<User> = []
users.insert(User(id: 1, username: "Tom"))
users.insert(User(id: 2, username: "Jerry"))
// User(id: 1, username: "Tom") == User(id: 1, username: "Tom") → true
        此时,Swift 自动合成的等价代码:
            
            
              swift
              
              
            
          
          extension User {
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
        hasher.combine(username)
    }
    static func == (lhs: User, rhs: User) -> Bool {
        return lhs.id == rhs.id && lhs.username == rhs.username
    }
}
        自定义哈希逻辑
有时你只希望根据关键字段判断相等性,例如只按 id 判断唯一性:
            
            
              swift
              
              
            
          
          struct Product: Hashable {
    let id: Int
    let name: String
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }
    static func == (lhs: Product, rhs: Product) -> Bool {
        return lhs.id == rhs.id
    }
}
        此时 Set 中即使 name 不同,只要 id 相同就认为是重复元素。
注意事项
- Hashable 自动合成仅适用于 所有属性都是 Hashable 的结构体或枚举;
 - 如果你手动实现了 hash(into:),就要确保 == 与哈希值的一致性(即"相等的对象必须有相同的哈希值");
 - 引用类型 class 也可以遵循 Hashable,但不会自动合成,需要你手动实现;
 - 如果类型不符合 Hashable,就不能作为 Set 元素或 Dictionary 的键,编译报错。
 
| 容器类型 | 元素/键的类型约束 | 
|---|---|
| Set | Element: Hashable | 
| Dictionary<Key, Value> | Key: Hashable | 
Identifiable 协议
什么是 Identifiable?
Identifiable 协议定义了一个稳定的唯一标识符。这在 SwiftUI 中尤其有用,用于标识列表(List、ForEach)中的元素。
语法定义
            
            
              swift
              
              
            
          
          protocol Identifiable {
    associatedtype ID: Hashable
    var id: ID { get }
}
        使用场景
- SwiftUI 的 
List和ForEach自动识别元素 - 标识数据库或网络对象
 - 建模唯一对象实体
 
示例
            
            
              swift
              
              
            
          
          struct Task: Identifiable {
    let id: UUID = UUID()
    let title: String
}
        在 SwiftUI 中的应用:
            
            
              swift
              
              
            
          
          struct TaskListView: View {
    let tasks = [
        Task(title: "Write Blog"),
        Task(title: "Read Book")
    ]
    var body: some View {
        List(tasks) { task in
            Text(task.title)
        }
    }
}
        Comparable 协议
什么是 Comparable?
遵循 Comparable 协议的类型可以进行大小比较,比如 <、<=、>、>=。它默认要求你实现 < 运算符。
语法定义
            
            
              swift
              
              
            
          
          protocol Comparable: Equatable {
    static func < (lhs: Self, rhs: Self) -> Bool
}
        使用场景
- 数组排序 
sorted()、sort() - 最值计算:
min、max - 排序操作中用作键值
 
示例
            
            
              swift
              
              
            
          
          struct Score: Comparable {
    let value: Int
    static func < (lhs: Score, rhs: Score) -> Bool {
        return lhs.value < rhs.value
    }
}
let scores = [Score(value: 10), Score(value: 30), Score(value: 20)]
let sorted = scores.sorted()
        你也可以让多个属性参与比较:
            
            
              swift
              
              
            
          
          struct Player: Comparable {
    let name: String
    let score: Int
    static func < (lhs: Player, rhs: Player) -> Bool {
        if lhs.score == rhs.score {
            return lhs.name < rhs.name
        }
        return lhs.score < rhs.score
    }
}
        总结
| 协议 | 作用 | 常见应用 | 
|---|---|---|
| Equatable | 判断两个值是否相等 | if 判断、查找、比较等 | 
| Hashable | 提供哈希值用于集合、字典等 | Set、Dictionary 的键、去重 | 
| Identifiable | 提供唯一标识符 | SwiftUI List、模型标识 | 
| Comparable | 值之间的大小关系比较 | 排序、筛选、最值计算等 | 
通过为你的自定义类型实现这些协议,不仅可以获得 Swift 提供的强大集合操作能力,还能让代码更具表达力与扩展性。
最后,希望能够帮助到有需要的朋友,如果觉得有帮助,还望点个赞,添加个关注,笔者也会不断地努力,写出更多更好用的文章。