我正在扩展struct
符合Hashable
。我将使用DJB2哈希合并器来完成此任务。
为了便于为其他事情编写哈希函数,我想扩展Hashable
协议,以便我的哈希函数可以像这样编写:
extension MyStruct: Hashable {
public var hashValue: Int {
return property1.combineHash(with: property2).combineHash(with: property3)
}
}
但是当我尝试将扩展名编写为实现`combineHash(with :)的Hashable
时,就像这样:
extension Hashable {
func combineHash(with hashableOther:Hashable) -> Int {
let ownHash = self.hashValue
let otherHash = hashableOther.hashValue
return (ownHash << 5) &+ ownHash &+ otherHash
}
}
...然后我得到这个编译错误:
/Users/benjohn/Code/Nice/nice/nice/CombineHash.swift:12:43:协议'Hashable'只能用作通用约束,因为它具有Self或相关类型要求
这是Swift不会让我做的事情,还是我只是做错了并得到一个无用的错误信息?
除了JAL的评论链接到a code review of a swift hash function,这也是马丁写的,提供下面接受的答案!他在讨论中提到了一个不同的哈希合并器,它基于c ++ boost库中的一个。讨论确实值得一读。替代组合器具有较少的冲突(在测试的数据上)。
如果P
是具有P
或相关类型要求的协议,则无法定义Self
类型的参数。在这种情况下,它是Equatable
继承的Hashable
协议,具有Self
要求:
public static func ==(lhs: Self, rhs: Self) -> Bool
您可以做的是定义一个通用方法:
extension Hashable {
func combineHash<T: Hashable>(with hashableOther: T) -> Int {
let ownHash = self.hashValue
let otherHash = hashableOther.hashValue
return (ownHash << 5) &+ ownHash &+ otherHash
}
}
使用Apple Developer Documentation中的方法hash(into :)
struct GridPoint {
var x: Int
var y: Int
}
extension GridPoint: Hashable {
static func == (lhs: GridPoint, rhs: GridPoint) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
func hash(into hasher: inout Hasher) {
hasher.combine(x)
hasher.combine(y)
}
}
这是文档的链接:https://developer.apple.com/documentation/swift/hashable