Swift 应该使用字符串散列来索引持久数据?

Swift String hash should be used to index persistent data?

我偶然发现了我(相对)旧代码中的一个错误,并发现字符串哈希 属性 被证明不是密集唯一的:许多不同的字符串具有相同的哈希值。

参考文档,我只找到"An unsigned integer that can be used as a hash table address",根本没有任何信息。

我的代码片段简单如下:

func getCacheIndex(sUrl: String) -> Int {
   return sUrl.hash
}

并针对给定的不同字符串生成以下内容(标题参数不同,而 XXXXXXX 表示替换的密钥字符串):

FileCache hash is -4052854053573130360 for url
 https://maps.googleapis.com/maps/api/streetview?size=675x900&location=46.414382,10.013988&heading=135&pitch=-0.76&key=XXXXXXXXXXXXXXXXXXX 

FileCache hash is -4052854053573130360 for url
 https://maps.googleapis.com/maps/api/streetview?size=675x900&location=46.414382,10.013988&heading=180&pitch=-0.76&key=XXXXXXXXXXXXXXXXXXX

String 有一个 hashValue,但它明确指出我们不应该使用它来持久化运行之间的任何内容。

你如何用 Swift 解决这个问题?我应该提供自己的哈希码吗?

我暂时用我的应用程序中的自定义功能替换了原生 String.hash。这解决了问题,具有更好的表观分布:

public func hash(_ string: String) -> Int {
    func djb(_ string: String) -> Int {

        return string.utf8
            .map {return [=10=]}
            .reduce(5381) {
                ([=10=] << 5) &+ [=10=] &+ Int()
        }
    }

    return djb(string)
}

注意:djb hash func 可以在我有时间进行分发时随时更换。

Swift 4

extension String {
    var persistantHash: Int {
        return self.utf8.reduce(5381) {
            ([=10=] << 5) &+ [=10=] &+ Int()
        }
    }
}

用法示例:

"my-string".persistantHash