1

在项目中,我们使用模型层的类,因此我必须编写如下代码:

// 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)
    }
}

这个样板可以以某种方式避免吗?默认情况下是否可以实现该Equatable比较?.hashValue谢谢。

4

2 回答 2

6

这是错误的,编译器自动合成它是没有意义的:

static func == (lhs: Player, rhs: Player) -> Bool {
    return lhs.hashValue == rhs.hashValue
}

相同的对象必须具有相同的哈希值,但不能相反:不同的对象可以具有相同的哈希值。

具体来说,在您的示例中:名称是一个字符串,并且有无数个不同的字符串,但只有 2 64 个不同的哈希值。所以必须有两个不同的字符串具有相同的哈希值。

如果所有存储的属性都是,Hashable那么编译器可以为您完全合成一致性。例如

struct Player : Equatable, Hashable {
    let name: String
    var score: Int
}

如果两个玩家具有相同的名字和相同的分数,则这里的两个玩家是“相同的”。

如果有不可散列的属性,或者如果您想自定义身份的概念,那么您必须相应地== 覆盖 hash(into)。散列函数应该使用确定身份的相同属性==。例如

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)
    }
}

现在,如果两个玩家的名字相同,则他们是“相同的”。

于 2019-06-11T09:21:43.287 回答
0

您可以通过 Stencil 标记语言编写自定义模板,并使用 Sourcery 库自动生成代码。

或者使用现有的解决方案(AutoEquatable、AutoHashable Sourcery 模板)。

你也可以这样写:

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)
    }
}

它将帮助您避免在不同类别中的重复。

于 2019-06-11T10:41:30.027 回答