Avoid Equatable and Hashable boilerplate, Swift 4.2

 ̄綄美尐妖づ 提交于 2019-12-11 04:25:33

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!