Equatable, Hashable与Comparable

4周前 38次点击 来自 Swift

Equatable, HashableComparable是笔者高频使用到的3个协议,且它们3者有类似的功能,相关联度较高,故在此进行学习小结

  • Equatable 判断2个对象是否相等或不等(==/!=)
  • Hashable 判断2个对象Hash值是否一样
  • Comparable 比较2个对象大小

Hashable继承至Equatable,2者具有以下的充要关系:

  • 2个对象相等,hash一定相等
  • 2个对象hash相等,2者不一定相等

所以根据以上特性,假设在一个集合Set中,Swift判断新加入的对象是否重复,则先判断hash是否有重复,如果hash值没有重复则加入这个新对象,如果hash相等,那么调用Equatable的实现进行下一步对比。

1.Equatable, Hashable的自动合成(Automatic Synthesis)

Swift4.1之后,Equatable, Hashable的自动合成支持了自动合成,无需再实现相关方法。

struct Person: Equatable, Hashable {
    var name: String
    var gender: String
    var age: Int
}

Swift自动合成类似如下:

struct Person: Equatable, Hashable {
    var name: String
    var gender: String
    var age: Int

    //此处省略!= 的实现 
    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name && lhs.gender == rhs.gender && lhs.age == rhs.age
    }

    //var hashValue: Int 已弃用
    func hash(into hasher: inout Hasher) {
        hasher.combine(name)
        hasher.combine(gender)
        hasher.combine(age)
    }
}

也就是说如果,我们需要实现自己的EquatableHashable规则,则按上例进行自定义即可。

当一个类实现了Equatable之后,你可以在集合中判断是否存在相同对象,最好用的地方就是你能将它使用在switch判断中:

let person0 = Person(name: "devler", gender: "male", age: 1)
let person1 = Person(name: "devler", gender: "male", age: 18)
let person2 = Person(name: "devler", gender: "male", age: 60)

[person0, person1, person2].contains(person0)

func age(for person: Person) -> String? {
    switch person {
    case person0: return "童雷"
    case person1: return "少雷"
    case person2: return "老雷"
    default: return nil
    }
}

age(for: person0)

2.Comparable

Comparable则不支持自动合成,它支持以下4个操作符:

操作符 解释
< 小于
<= 小于等于
> 大于
>= 大于等于

所以如果我们需要对比2个对象的大小,只需要实现 < 方法:

static func < (lhs: Person, rhs: Person) -> Bool

例如:

extension Person: Comparable {
    static func < (lhs: Person, rhs: Person) -> Bool {
        if lhs.age != rhs.age {
            return lhs.age < rhs.age
        } else {
            return lhs.name < rhs.name
        }
    }
}

let person0 = Person(name: "devler", gender: "male", age: 1)
let person1 = Person(name: "devler", gender: "male", age: 18)
let person2 = Person(name: "devler", gender: "male", age: 60)

person1 > person0
person1 > person2

实现了Comparable协议,我们就可以做排序和最大最小相关的操作:

var persons = [person1, person0, person2]
persons.sort()
persons.min()
persons.max()
Card image cap
开发者雷

尘世间一个小小的开发者

技术文档 >> 系列应用 >>
热推应用

EntryS

学习Swift的入门教程
标签