23

我正在尝试创建一个字典,其中键作为我创建的结构,值作为 Ints 数组。但是,我不断收到错误消息:

类型“DateStruct”不符合协议“Hashable”

我很确定我已经实现了必要的方法,但由于某种原因它仍然不起作用。

这是我实现协议的结构:

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

有人可以向我解释为什么我仍然收到错误吗?

4

6 回答 6

35

您缺少声明:

struct DateStruct: Hashable {

而且你的==功能是错误的。您应该比较这三个属性。

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

两个不同的值可能具有相同的哈希值。

于 2017-02-22T04:53:49.547 回答
13

顺便提一句

var hashValue: Int 

已过时(遗留的 NSObject 继承树除外)。

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

是新的方式

于 2020-06-04T15:43:33.680 回答
6

如果您不想使用 hashValue,您可以将值的哈希值与hash(into:)方法结合起来。

有关更多信息,请参阅答案:https ://stackoverflow.com/a/55118328/1261547

于 2019-03-12T09:50:16.813 回答
3

如果该类具有类型的字段(另一个类),则该类应采用 Hashable。

例子

struct Project : Hashable {
    var activities: [Activity]?

}

这里,Activity 类也必须采用 Hashable。

于 2021-03-01T11:13:23.377 回答
1

对于简单的结构,它的所有属性都已经存在Hashable(即Int,,String...),我们可以Hashable只声明它(参见https://developer.apple.com/documentation/swift/hashable

所以不需要实现hashValue(顺便说一句已被弃用)也不需要==(因为Hashable符合Equatable)。

并且由于我们正在实现<运算符,因此符合 是有意义的Comparable,因此我们可以排序(即[dateStructA, dateStructB, ...].sorted())。

所以我会这样做:

struct DateStruct: Comparable & Hashable {
    let year: Int
    let month: Int
    let day: Int

    static func < (lhs: DateStruct, rhs: DateStruct) -> Bool {
        if lhs.year != rhs.year {
           return lhs.year < rhs.year
        } else if lhs.month != rhs.month {
           return lhs.month < rhs.month
        } else {
           return lhs.day < rhs.day
        }
    }
}
于 2020-08-30T07:20:33.863 回答
1

定义结构时没有指定 Hashable 协议:

struct DateStruct: Hashable { ...

以下代码来自您的示例,它在 Playground 上运行。请注意,您的 == 运算符已在此处修改

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
于 2017-02-22T04:55:45.893 回答