避免使用Equatable和Hashable样板,Swift 4.2

时间:2019-06-11 09:03:04

标签: swift swift4.2 equatable

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

// 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进行比较?谢谢。

2 个答案:

答案 0 :(得分:4)

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

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

现在,如果两个球员的名字相同,那么他们是“相同的”。

答案 1 :(得分: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)
    }
}

它将帮助您避免在不同的班级重复。