swift Equatable
2024-04-09 18:10:28  阅读数 825

我来了,swift

定义

用于做值类型对比的协议。

适用范围

遵循Equatable的类型都可以使用==或是!=符号对比判断。这个类型包括struct/class/enum

实现原理

任何遵循Equatable的类型,都需要实现方法static func ==(lhs: Self, rhs: Self) -> Bool在这个方法内按照指定的值和值间对比关系返回true或是false,外部表现为==或是!=的结果

struct Human: Equatable {
    var name: String
    var age = 5
    
    static func == (lhs: Self, rhs: Self) -> Bool {
        return lhs.name == rhs.name
    }
}

let tom = Human(name: "tom", age: 5)
let tim = Human(name: "tim", age: 6)
tom == tim // false

let man1 = Human(name: "tom", age: 5)
let man2 = Human(name: "tom", age: 6)
man1 == man2 // true

Human对Equatable方法定义为只判断name属性是否值相同,即使age属性不同,man1==man2结果是true

在不同类型中的差异

  • class遵循Equatable必须要实现static func ==(lhs: Self, rhs: Self) -> Bool方法。但是,struct遵循Equatable可以不用实现static func ==(lhs: Self, rhs: Self) -> Bool方法,默认将struct实例中所有属性对比并返回结果
struct Dog: Equatable {
    var name: String
    var age = 0
}

let dog1 = Dog(name: "tom", age: 1)
let dog2 = Dog(name: "tom", age: 1)
dog1 == dog2  // true

let dog3 = Dog(name: "tom", age: 1)
let dog4 = Dog(name: "tom", age: 2)
dog3 == dog4  // false

struct Dog遵循Equatable协议但没有实现协议方法其实例dog1与dog2实例相等,dog3与dog3实例不相等

  • 数组等容器类(数组/字典等)内部的元素需要遵循Equatable才能实现一些能力,例如contains(_:)
let students = ["Kofi", "Abena", "Efua", "Kweku", "Akosua"]

let nameToCheck = "Kofi"
if students.contains(nameToCheck) {
    print("\(nameToCheck) is signed up!")  // Prints "Kofi is signed up!"
} else {
    print("No record of \(nameToCheck).")
}

  • swift standard library中的大部分基础类型默认已经遵循Equatable,例如Int/Array/Dictionary/Set
  • struct重的属性如果有不遵守Equatable,那么其实例无法用==
class MyClassNoEquatable {
    
}

struct NoEquatableStruct: Equatable {
    var mc = MyClassNoEquatable()
    
}

let nes1 = NoEquatableStruct()
let nes2 = NoEquatableStruct()
nes1 == nes2

上面代码会报错,提示Type 'NoEquatableStruct' does not conform to protocol 'Equatable'

协议间的关联

Hashable协议基于Equatable协议,对于struct遵守Hashable并不需要实现Equatable方法,但是对于class遵守Hashable必须要实现Equatable的方法
Comparable协议基于Equatable

=====

  • Equatable本质是对属性的值对比,适用范围有struct/class/enum
  • ===是对class实例指针的对比,且仅适用于class实例
class IntegerRef: Equatable {
    let value: Int
    init(_ value: Int) {
        self.value = value
    }

    static func == (lhs: IntegerRef, rhs: IntegerRef) -> Bool {
        return lhs.value == rhs.value
    }
}
let a = IntegerRef(100)
let b = IntegerRef(100)

print(a == a, a == b, separator: ", ") // Prints "true, true"

let c = a
print(c === a, c === b, separator: ", ") // Prints "true, false"

参考

Equatable
Swift Equatable