【问题标题】:Swift: Hashable struct with dictionary propertySwift:具有字典属性的可散列结构
【发布时间】:2016-10-26 08:00:30
【问题描述】:

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

我现在需要使用 MapKey 作为 Swift 字典中的键,这需要 MapKey 符合 Hashable 协议。

对于像这样的结构,Hashable 的正确实现是什么?

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

我一直在做一些研究,但未能确定散列字典的正确方法是什么,因为我需要能够为 values 属性本身生成散列值。非常感谢任何帮助。

【问题讨论】:

    标签: swift hashable equatable


    【解决方案1】:

    如果您必须使用整个结构作为字典键,我认为您需要检查您的数据模型。无论如何,这是一种方法:

    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
    }
    

    这假定您在 idvalues 的键和值中没有分号 (;)。 Hasable 暗示 Equatable 所以你不需要再次声明它符合Equatable

    【讨论】:

    • 你不需要对分号做任何假设(也不需要插入这样的分隔符),因为哈希不需要是唯一的。
    • 同意@MartinR。感谢代码的想法,这将解决我当前的需求,感谢您审查数据模型的建议,并牢记这一点。
    • 如果我错了,请纠正我。阅读此answer 我认为您确实需要再次单独实现 Equatable
    • @Honey 您不必声明与 Equatable 的一致性,因为 Hashable 已经暗示了这一点。 == 函数提供了 Equatable 所需的实现。
    • @CodeDifferent 不正是链接答案告诉您的应该吗?我的意思是,如果你的哈希值是相同的,那么它会切换到等价函数并尝试。或者是关于另一件事?你能解释一下吗?
    【解决方案2】:

    由于 id 和 values 都是不可变的,两者都可以用作 equals 和 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
        }
    

    【讨论】:

    • 很好的观察埃里克。不幸的是,在我的情况下,正是 id + values 的组合使 Key 独一无二,即使 id 会让你不这么认为。我可能没有为我的例子选择最好的名字。
    【解决方案3】:

    基础数据类型在 Swift 4.2 中是 Hashable,你只需要让你的 MapKey 结构符合 Hashable 协议:

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

    如果你想使用一个类,你需要像这样遵循 hash(:) 函数:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-09
      • 2013-04-15
      • 2020-03-08
      • 1970-01-01
      • 2018-08-21
      • 2010-11-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多