「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战」。
Equatable
Equatable 是一个检查您的自定义对象是否相等的协议,一种可以比较类型的值是否相等的协议。也就是说,符合 Equatable 协议的类型可以使用等号运算符 (==) 或不等运算符 (!=) 来比较相等性。swift 标准库的大部分基本数据类型都遵循 Equatable。Equatable协议是可以被某种类型采用的,类型就可能是类、结构体、枚举。元组等。
public protocol Equatable {
static func == (lhs: Self, rhs: Self) -> Bool
static func != (lhs: Self, rhs: Self) -> Bool
}
struct
默认用法:只要让结构体遵从Equatable 协议 ,自定义用法:static function == 即可;
struct Dog: Equatable{
var name : String
}
truct XWPerson: Equatable {
var name: String
var dog: Dog
var id : String
static func == (lhs: XWPerson, rhs: XWPerson) -> Bool {
return lhs.id == rhs.id
}
}
至于为什么需要用自定义用法呢,在上面这个例子就简单的说明了,因为一个人他的姓名、狗都不能改变,而这些改变就不能说不是同一个人了。所以我们只需要判断id是否相同即可。
enum
默认情况下:只要让 enum 遵从Equatable 协议,它就会在帮我们定义比对每一个 case 的 fuction ==,包含比对 associated value,只有全部相等时才才会返回true。然后跟上面的struct
一样我们可以根据实际情况自定义。
enum Status: Equatable {
case successed
case fail(reason:String)
static func == (lhs: Status, rhs: Status) -> Bool {
switch (lhs, rhs) {
case (.successed,.successed):
return true
case (.fail(let lreason), .fail(let rreason)):
return lreason == rreason
default:
return false
}
}
}
class
第一:我们可以跟前面的一样让 class 遵从Equatable 协议:看例子:
class Person: Equatable {
var name : String
init(_ name: String) {
self.name = name
}
static func == (lhs: Person, rhs: Person) -> Bool {
return lhs.name == rhs.name
}
}
let person1 = Person("Joke")
let person2 = Person("Joke")
let person3:Person? = Person("Joke")
print(person1 == person2) //true
print(person1 == person3) //true
第二:由于 NSObject 遵从Equatable协议,并且定义了变量的指针地址一样时 == 返回 true,所以我們想让自定义的 class 也能比较是否一样的話,只要继承NSObject 即可。
class Person: NSObject {
var name : String
init(_ name: String) {
self.name = name
}
}
let person1 = Person("Joke")
let person2 = Person("Joke")
let person3:Person? = Person("Joke")
print(person1 == person2) //true
print(person1 == person3) //false
这里你可以看到第二在可选类型判断时为false。这里其实牵扯协议的调度问题。对于上面的解决办法:
extension Person {
override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? Person else {
return false
}
return name == object.name
}
}
但是请注意isEqual
虽然能解决大部分问题,但是有些还是不行的哟。
元组
如果元组的所有元素都遵从Equatable,那么整个元组本身就符合Equatable。
(1, 2, 3) == (1, 2, 3) // true
struct NoEquatable {}
(NoEquatable(), 1, 2) == (NoEquatable(), 1, 2)
//error:Type '(NoEquatable, Int, Int)' cannot conform to 'Equatable'; only struct/enum/class types can conform to protocols
而且还需要注意的是如果元组都遵从Equatable,但是元组的key不一样,但是元组的值一样,则它们也是相等。
(x: 0, y: 0) == (0, 0) // true
这里留下一个话题:如何比较俩对象的一致性?有哪些方法?
AdditiveArithmetic
AdditiveArithmetic协议定义了简单的加法和减法。
protocol AdditiveArithmetic {
static var zero: Self
static func + (Self, Self) -> Self
static func += (Self, Self)
static func - (Self, Self) -> Self
static func -= (Self, Self)
}
是标准的数字类型Int等都是符合AdditiveArithmetic,也可以自定义符合AdditiveArithmetic的类型。
这里说一下Numeric。在swift新版本中将AdditiveArithmetic从Numeri抽取出来,这里就提前上一篇文章说到将协议尽量变小而且明确。比如这里有些事物只需要进行加法和减法的运算,而没有与乘法等效的运算。比如向量:
struct Vector3D {
typealias Scalar = Float
var x: Scalar
var y: Scalar
var z: Scalar
}
extension Vector3D : AdditiveArithmetic {
static var zero = Vector3D(x: 0, y: 0, z: 0)
static func + (lhs: Vector3D, rhs: Vector3D) -> Vector3D {
return Vector3D(x: lhs.x + rhs.x, y: lhs.y + rhs.y, z: lhs.z + rhs.z)
}
static func += (lhs: inout Vector3D, rhs: Vector3D) {
lhs = lhs + rhs
}
static func - (lhs: Vector3D, rhs: Vector3D) -> Vector3D {
return Vector3D(x: lhs.x - rhs.x, y: lhs.y - rhs.y, z: lhs.z - rhs.z)
}
static func -= (lhs: inout Vector3D, rhs: Vector3D) {
lhs = lhs - rhs
}
}
Comparable
Comparable协议对于对自定义数组进行排序非常方便。Comparable协议允许使用使用<,>,<=,和>=,这样可以让元素知道如何进行排序。
public protocol Comparable : Equatable {
static func < (lhs: Self, rhs: Self) -> Bool
static func <= (lhs: Self, rhs: Self) -> Bool
static func >= (lhs: Self, rhs: Self) -> Bool
static func > (lhs: Self, rhs: Self) -> Bool
}
比如对人按照年龄进行排序。
extension Person: Comparable {
static func < (lhs: Person, rhs: Person) -> Bool {
return lhs.age < rhs.age
}
}
Hashable
什么是哈希值 通过一定的计算程序从底层数据中得到的非常规的定长值。它用于加密和认证,但也适用于数据结构。它被称为哈希表或哈希映射。在swift 字典就是一个典型,准确的说是字典type 中有 Key 类型的限制,适配Hashable,保证哈希表中key的唯一性,可以保证比较和查找。
而Hashable协议是用于为自定义类型提供散列功能的主要组件。
public protocol Hashable : Equatable {
var hashValue: Int { get }
func hash(into hasher: inout Hasher)
}
继承hashable 协议有一个重要的原则:如果两个实例相等,则它们必须产生相同的哈希值。
如果a == b ,那么 a.hashValue == b.hashValue。
SetAlgebra
SetAlgebra 是一个用于集合操作(交集、并集等操作)的协议,它本身自定义的比较少,这里面它的继承里OptionSet用的比较多,因为它跟Objective-C的[NS_OPTIONS
]很像。
struct PetType: OptionSet {
let rawValue: Int
static let dog = PetType(rawValue: 1 << 0)
static let cat = PetType(rawValue: 1 << 1)
static let bird = PetType(rawValue: 1 << 2)
static let other = PetType(rawValue: 1 << 3)
}
PetType.cat