问题
On project we are using classes for model's layer and because of that I have to write code like this:
// MARK: - Hashable
extension Player: Hashable {
static func == (lhs: Player, rhs: Player) -> Bool {
return lhs.hashValue == rhs.hashValue
}
func hash(into hasher: inout Hasher) {
hasher.combine(self.name)
}
}
Can this boilerplate can be somehow avoided? Is it possible to implement that Equatable
compare by .hashValue
by default? Thanks.
回答1:
You could write your custom template via Stencil markup language and autogenerate the code using the Sourcery library.
Or use the existing solutions (AutoEquatable, AutoHashable Sourcery templates).
And also you could write something like this:
protocol IHash: class { }
extension IHash where Self: Hashable {
static func ==(lhs: Self, rhs: Self) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
class User: IHash, Hashable {
var name: String = ""
func hash(into hasher: inout Hasher) {
hasher.combine(self.name)
}
}
It will help you to avoid duplication in different classes.
回答2:
This is wrong, and it would make no sense that the compiler synthesizes it automatically:
static func == (lhs: Player, rhs: Player) -> Bool {
return lhs.hashValue == rhs.hashValue
}
Identical objects must have the same hash value, but not the other way around: Distinct objects can have the same hash value.
Concretely, in your example: The name is a string and there are infinitely many different strings, but only 264 different hash values. So there must be two different strings with the same hash value.
If all stored properties are Hashable
then the compiler can synthesize the conformance for you completely. For example
struct Player : Equatable, Hashable {
let name: String
var score: Int
}
Here two players are “identical” if they have the same name and the same score.
If there are non-hashable properties, or if you want to customize the concept of identity then you have to override ==
and hash(into)
accordingly. The hash function should use the same properties which determine the identity in ==
. For example
struct Player : Equatable, Hashable {
let name: String
var score: Int
static func == (lhs: Player, rhs: Player) -> Bool {
return lhs.name == rhs.name
}
func hash(into hasher: inout Hasher) {
hasher.combine(self.name)
}
}
Now two players are “identical” if they have the same name.
来源:https://stackoverflow.com/questions/56540092/avoid-equatable-and-hashable-boilerplate-swift-4-2