0

I have a struct, Student that conforms to Hashable protocol but I am getting an error for the hash(into:) method.

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

I am getting error for the function hash(into:). As Student is a struct not class, I am confused on how to implement the required hash(into:) function. Can anyone please help me.

Natasha
  • 6,651
  • 3
  • 36
  • 58

2 Answers2

3

Here it is for your case

func hash(into hasher: inout Hasher){
    hasher.combine(studentID)
    hasher.combine(name)
}
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • Thank you. This worked. However from my code, it was not clear that the studentID is unique, so I just need to combine studentID. – Natasha May 10 '20 at 13:04
0

The simplest form is

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

You get the initializer, Equatable (the == operator) and hash(into) for free. The hasher considers all struct members.

If you want only studentID to be considered write

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)
    }
}
vadian
  • 274,689
  • 30
  • 353
  • 361
  • In your second solution you must also override `==`. – Martin R May 10 '20 at 13:43
  • Only considering `studentID` here would violate Equatable: "Equality implies substitutability—any two instances that compare equally can be used interchangeably in any code that depends on their values. To maintain substitutability, the == operator should take into account all visible aspects of an Equatable type." I don't believe Identifiable gives you Equatable (and shouldn't, since it only tests `id`). – Rob Napier May 10 '20 at 13:57
  • @RobNapier `Identifiable` conforms to `Equatable` and synthesizes `==` based on `id`. – vadian May 10 '20 at 14:01
  • 1
    @vadian Can you double-check that? I don't see Identifiable requiring Equatable in the stdlib, or in my playground experiments. `struct X: Identifiable { var id: Int }; X(id: 1) == X(id: 2)` returns the error I expect: `Binary operator '==' cannot be applied to two 'X' operands`. Is there an extension in SwiftUI or something I'm missing? – Rob Napier May 10 '20 at 15:11
  • @RobNapier My bad, I was under the impression that `Identifiable` adds `Equatable` implicitly, because the required `id` property must be `Hashable`, sorry. – vadian May 10 '20 at 15:24