Как реализовать хеш (в хэш: inout Hasher) для структуры

У меня есть struct, студент, который соответствует протоколу Hashable, но я получаю сообщение об ошибке для метода hash(into:).

struct Student: Hashable{
    let studentID: Int
    let name: String

    init(studentID id:Int, andName name: String){
        studentID = id
        self.name = name
    }
    func hash(into hasher: inout Hasher){
        hasher.combine(bytes: ObjectIdentifier(self.Type)) //giving compile-time error
    }
    static func == (lhs: Self, rhs: Self) -> Bool{
        return (lhs == rhs)
    }
}

Я получаю сообщение об ошибке для функции hash(into:). Поскольку Student - это структура, а не класс, я не понимаю, как реализовать требуемую функцию hash(into:). Кто-нибудь может мне помочь, пожалуйста.


person Natasha    schedule 10.05.2020    source источник


Ответы (2)


Вот для вашего случая

func hash(into hasher: inout Hasher){
    hasher.combine(studentID)
    hasher.combine(name)
}
person Asperi    schedule 10.05.2020
comment
Спасибо. Это сработало. Однако из моего кода не было ясно, что идентификатор студента уникален, поэтому мне просто нужно объединить идентификатор студента. - person Natasha; 10.05.2020

Самая простая форма это

struct Student: Hashable {
    let studentID: Int
    let name: String
}

Вы получаете инициализатор, Equatable (оператор ==) и hash(into) бесплатно. Хэшер рассматривает все члены структуры.

Если вы хотите, чтобы учитывались только studentID, напишите

struct Student: Hashable {
    let studentID: Int
    let name: String

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

    func hash(into hasher: inout Hasher) {
        hasher.combine(studentID)
    }
}
person vadian    schedule 10.05.2020
comment
Во втором решении вы также должны переопределить ==. - person Martin R; 10.05.2020
comment
Только рассмотрение studentID здесь нарушило бы Equatable: равенство подразумевает взаимозаменяемость — любые два экземпляра, которые одинаково сравниваются, могут использоваться взаимозаменяемо в любом коде, который зависит от их значений. Чтобы поддерживать заменяемость, оператор == должен учитывать все видимые аспекты типа Equatable. Я не верю, что Идентифицируемый дает вам Equatable (и не должен, так как он проверяет только id). - person Rob Napier; 10.05.2020
comment
@RobNapier Identifiable соответствует Equatable и синтезирует == на основе id. - person vadian; 10.05.2020
comment
@vadian Можете ли вы перепроверить это? Я не вижу, чтобы Идентифицируемый требовал Equatable в stdlib или в моих экспериментах на игровой площадке. struct X: Identifiable { var id: Int }; X(id: 1) == X(id: 2) возвращает ожидаемую ошибку: Binary operator '==' cannot be applied to two 'X' operands. Есть ли расширение в SwiftUI или что-то, чего мне не хватает? - person Rob Napier; 10.05.2020
comment
@RobNapier Плохо, у меня сложилось впечатление, что Identifiable неявно добавляет Equatable, потому что требуемое свойство id должно быть Hashable, извините. - person vadian; 10.05.2020