Equals 是一个 Swift µ框架,旨在在符合 Equatable 和 Hashable 协议时减少样板代码。
将其添加到您的 Package.swift 依赖关系
import PackageDescription
let package = Package(
// ... your project details
dependencies: [
// As a required dependency
.Package(url: "ssh://[email protected]/tomquist/Equals.git", majorVersion: 2)
],
testDependencies: [
// As a test dependency
.Package(url: "ssh://[email protected]/tomquist/Equals.git", majorVersion: 2)
]
)
我们从一个非常简单的结构体开始
struct Person {
let firstName: String?
let lastName: String
let children: [Person]
}
为了使此类型符合 Equatable
,我们首先必须声明遵从性,例如通过提供一个空的扩展并提供 ==
操作符的重载
extension Person: Equatable {}
func ==(lhs: Person, rhs: Person) -> Bool {
return lhs.firstName == rhs.firstName
&& lhs.lastName == rhs.lastName
&& lhs.children == rhs.children
}
如你所见,这为这样一个简单的类型写了很多代码,并且每个属性都被列出两次。
更糟的是,当遵循 Hashable
时,你还需要提供一个复杂的 hashValue
属性
extension Person: Hashable {
var hashValue: Int {
var result = 17
result = 31 &* result &+ (firstName?.hashValue ?? 0)
result = 31 &* result &+ lastName.hashValue
for child in children {
result = 31 &* result &+ child.hashValue
}
return result
}
}
使用 Equals,这变得容易得多。为了符合 Hashable
,你需要做的只是遵守 EqualsHashable
协议
extension Person: EqualsHashable {
static let hashes: Hashes<Person> = Hashes()
.append {$0.firstName}
.append {$0.lastName}
.append {$0.children}
}
如果你不需要哈希功能,只需遵守 EqualsEquatable
协议即可
extension Person: EqualsEquatable {
static let equals: Equals<Person> = Equals()
.append {$0.firstName}
.append {$0.lastName}
.append {$0.children}
}
就是这样!现在你可以使用 ==
操作符比较你的类型,将它放入 Set
中,或者将其用作 Dictionary
的键。
Equals 当前提供了四种类型的属性的 append
函数
Equatable
/Hashable
属性Equatable
/Hashable
的 Optional
属性Equatable
/Hashable
的 CollectionType
属性有时,你必须明确指定要使用哪个 append 方法。例如,让我们将上面示例中的 Person
的 children
属性更改为类型 Set<Person>
。因为 Set
已经遵循了 Hashable
,我们现在会得到编译器错误
Ambiguous use of 'append(hashable:)'
这是因为在此情况下可能有几种可用的 append
方法。为了避免这个错误,我们可以将我们的 EqualsHashable
实现改变为以下内容
extension Person: EqualsHashable {
static let hashes: Hashes<Person> = Hashes()
.append {$0.firstName}
.append {$0.lastName}
.append(hashable: {$0.children})
}