Swift Tips 005 - Using Wrap to implement Equatable

每天了解一点不一样的 Swift 小知识

代码截图

小笔记

Equatable 是什么

简单来说,Equatable 是 Swift 中用来判断 2 个对象是否相等(或者不相等)的描述。

在程序员眼里,相等似乎也有 2 个标准,一个是两个对象是否指向同一块内存地址,另一个是对象的内容是否符合我们定义的”相等”,下面的例子中的相等是指后者。

总结一下就是说:在 Swift 中的 == 是用来判断 2 个对象的内容是否相等(类似 Objective-C 里的 isEqual 的 API),而 === 是用来判断 2 个对象是否指向同一块内存地址(类似Objective-C 中的 ==

扩展阅读:判等

Equatable 怎么用

很显然在 Swift 的世界里,并不是所有东西都可以用 == 进行判断,例如:

struct Man {
var name: String
var height: Double
}
let man1 = Man(name: "张思琦", height: 180.5)
let man2 = Man(name: "宋旭陶", height: 180.5)
if man1 == man2 {
}

如果真的想要使用 == 比较,也并没有那么难,只需要让类型遵循 Equatable 的 protocol 并定义 static function == ,例如刚才的例子,我们完善一下 Man 的定义

struct Man: Equatable {
var name: String
var height: Double
static func == (lhs: Man, rhs: Man) -> Bool {
return lhs.name == rhs.name && lhs.height == rhs.height
}
}

在这个例子中,我们两个人的身高和名字完全相同则两个人完全相等,即用 == 进行判断时能够返回 true

protocol + extension 怎么就实现任意类型的 equatable 了

在 Swift 中,我们可以对 protocol 进行 extension ,通过 extension 来实现一部分需求或者实现一些附加功能,这样遵循该 protocol 的类型就拥有了相应的能力。

图片里的代码就是利用 protocol & extension 这种形式,为所有遵循此协议的类型提供了一个默认的 Equatable 实现,只需要遵守此协议就可以使用 Equatable 了。

虽然 Swift 和 Objective-C 都有 protocol ,extension 的概念,但是两者有一定的区别。

同样为不同类型添加默认的 extension 功能,我们可能需要将相关代码写在不同类型的统一基类或者写在遵守对应 protocol 的类型中,相比于Swift 来说,Objective-C 的这种设计就显得没那么优雅了。

扩展阅读:在扩展里添加协议遵循

wrap 是什么

wrap() 是一个第三方 Swift 库的 API,这个库的名字叫做 Wrap,主要用于 JSON 的解析,它的链接如下:https://github.com/johnsundell/wrap

那么 Wrap 到底有什么用呢

试想一下在 Swift 4.1 之前,如果你要判断 2 个类型(里面有10 个属性)相等,你需要在 == 的定义里写 10 个判断,这是一段又臭又长的代码。。。

而用了 Wrap 之后,你无须关心相关类型的具体形式,只需要调用:

let lhsData = try! wrap(lhs) as Data
let rhsData = try! wrap(rhs) as Data
lhsData == rhsData

不过在 Swift 4.1 之后,Swift 添加了一个新功能,只要 struct 遵循了 Equatable 的 protocol,那么它就会自动帮我们定义比对每一个 property 的 function ==,只要全部相等时,才返回 true,所以代码可以变得更加优雅了(这个功能目前也支持了 Enum 类型)

struct Man: Equatable {
var name: String
var height: Double
var weight: Double
var age: Int
}

具体的 proposal 可以查看 Synthesizing Equatable and Hashable conformance