-->

Conforming to Hashable protocol?

2020-08-11 10:38发布

问题:

I'm trying to make a dictionary with the key as a struct I've created and the value as an array of Ints. However, I keep getting the error:

Type 'DateStruct' does not conform to protocol 'Hashable'

I'm pretty sure I've implemented the necessary methods but for some reason it still doesn't work.

Here's my struct with the implemented protocols:

struct DateStruct {
    var year: Int
    var month: Int
    var day: Int

    var hashValue: Int {
        return (year+month+day).hashValue
    }

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

    static func < (lhs: DateStruct, rhs: DateStruct) -> Bool {
        if (lhs.year < rhs.year) {
            return true
        } else if (lhs.year > rhs.year) {
            return false
        } else {
            if (lhs.month < rhs.month) {
                return true
            } else if (lhs.month > rhs.month) {
                return false
            } else {
                if (lhs.day < rhs.day) {
                    return true
                } else {
                    return false
                }
            }
        }
    }
}

Can anybody please explain to me why I'm still getting the error?

回答1:

You're missing the declaration:

struct DateStruct: Hashable {

And your == function is wrong. You should compare the three properties.

static func == (lhs: DateStruct, rhs: DateStruct) -> Bool {
    return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day
}

It's possible for two different values to have the same hash value.



回答2:

If you don't want to use the hashValue, you can combine the hash of your values with the hash(into:) method.

For more information see the answer : https://stackoverflow.com/a/55118328/1261547



回答3:

Btw

var hashValue: Int 

is obsolete (except in the legacy NSObject inheritance trees).

func hash(into hasher: inout Hasher)
    {
        hasher.combine(year);
        hasher.combine(month) 
    ...

is the new way



回答4:

You did not specified the Hashable protocol when defining struct:

struct DateStruct: Hashable { ...

The following code is from your example and it runs on a Playground. Please note that your == operator has been modified here:

import Foundation

struct DateStruct: Hashable {
    var year: Int
    var month: Int
    var day: Int

    var hashValue: Int {
        return (year+month+day).hashValue
    }

    static func == (lhs: DateStruct, rhs: DateStruct) -> Bool {
        return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day
    }

    static func < (lhs: DateStruct, rhs: DateStruct) -> Bool {
        if (lhs.year < rhs.year) {
            return true
        } else if (lhs.year > rhs.year) {
            return false
        } else {
            if (lhs.month < rhs.month) {
                return true
            } else if (lhs.month > rhs.month) {
                return false
            } else {
                if (lhs.day < rhs.day) {
                    return true
                } else {
                    return false
                }
            }
        }
    }
}

var d0 = DateStruct(year: 2017, month: 2, day: 21)
var d1 = DateStruct(year: 2017, month: 2, day: 21)

var dates = [DateStruct:Int]()
dates[d0] = 23
dates[d1] = 49

print(dates)

print(d0 == d1) // true

d0.year = 2018

print(d0 == d1) // false