简体   繁体   English

Swift:具有字典属性的Hashable结构

[英]Swift: Hashable struct with dictionary property

I have a struct in Swift that looks like this: 我在Swift中有一个结构,如下所示:

internal struct MapKey {
    internal let id: String
    internal let values: [String:String]
}
extension MapKey: Equatable {}
func ==(lhs: MapKey, rhs: MapKey) -> Bool {
    return lhs.id == rhs.id && lhs.values == rhs.values
}

I now have the need to use MapKey as the key in a Swift dictionary, which requires MapKey to conform to the Hashable protocol. 我现在需要使用MapKey作为Swift字典中的键,这需要MapKey符合Hashable协议。

What would a correct implementation of Hashable be for a struct like this one? 对于像这样的结构,Hashable的正确实现是什么?

extension MapKey: Hashable {
    var hashValue: Int {
        return ??? // values does not have a hash function/property.
    }
}

I've been doing some research but failed to identify what the proper way to hash a dictionary is, as I need to be able to generate a hash value for values property itself. 我一直在做一些研究,但未能确定散列字典的正确方法是什么,因为我需要能够为values属性本身生成散列值。 Any help is much appreciated. 任何帮助深表感谢。

I think you need to review your data model if you have to use a whole struct as a dictionary key. 我认为如果必须使用整个结构作为字典键,则需要检查数据模型。 Anyhow, here's one way to do it: 无论如何,这是一种方法:

internal struct MapKey: Hashable {
    internal let id: String
    internal let values: [String:String]

    var hashValue: Int {
        get {
            var hashString = self.id + ";"
            for key in values.keys.sort() {
                hashString += key + ";" + values[key]!
            }

            return hashString.hashValue
        }
    }
}

func ==(lhs: MapKey, rhs: MapKey) -> Bool {
    return lhs.id == rhs.id && lhs.values == rhs.values
}

This assumes that you don't have semicolon ( ; ) in id or in the keys and values of values . 这假设您在id或键的values和值中没有分号( ; )。 Hasable implies Equatable so you don't need to declare it conforming to Equatable again. Hasable意味着Equatable所以你不需要声明它再次符合Equatable

Since both id and values are immutable both are ok to use as basis for equals and hashValue. 由于id和值都是不可变的,因此可以将它们用作equals和hashValue的基础。 However - if MapKey.id (which the name somewhat implies) uniquely identifies the MapKey (at least within the context of one dictionary) then it is both easier and more performant to just use the MakKey.id as basis for == operator as well as hashValue 但是 - 如果MapKey.id(名称有点暗示)唯一地标识MapKey(至少在一个字典的上下文中),那么仅使用MakKey.id作为==运算符的基础也更容易且更高效。作为hashValue

    internal struct MapKey: Hashable {
        internal let id: String
        internal let values: [String:String]

        var hashValue: Int {
            get { return  self.id.hashValue}
        }
    }

    func ==(lhs: MapKey, rhs: MapKey) -> Bool {
        return lhs.id == rhs.id
    }

foundation data types are Hashable in Swift 4.2, you only need to let your MapKey struct to conform Hashable protocol: 基础数据类型在Swift 4.2中是Hashable,你只需要让你的MapKey结构符合Hashable协议:

struct MapKey: Hashable {
    let id: String
    let values: [String: String]
}

in case you want to use a class, you need conform hash(:) func like this: 如果你想使用一个类,你需要符合hash(:) func,如下所示:

class MapKey: Hashable {
    static func == (lhs: MapKey, rhs: MapKey) -> Bool {
        return lhs.id == rhs.id && lhs.values == rhs.values
    }

    let id: String = ""
    let values: [String: String] = [:]

    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
        hasher.combine(values)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM