在Swift 3中实现Java String的hashCode()方法

6

我正在为一款现有的Android应用程序创建iOS版本。在Android端,一个字符串(用户名)的hashCode()被发送到服务器,基于该哈希值返回一个JSON对象。

在Swift中,我尝试使用hash和hashValue属性,但是它们产生的值与其Android对应物不同。

因此,我决定根据Java的实现编写自己的实现:

int h = hash;
if (h == 0 && value.length > 0) {
  char val[] = value;
  for (int i = 0; i < value.length; i++) {
    h = 31 * h + val[i];
  }
  hash = h;
}
return h;

但是,当我用Swift编写上述实现时,会出现溢出崩溃。有人能帮我吗?

提前感谢。

这是Swift的实现:

我首先必须编写一个Character扩展,该扩展将返回字符的Ascii值:

extension Character {
    var asciiValue: UInt32? {
        return String(self).unicodeScalars.filter{$0.isASCII}.first?.value
    }
}

那我创建了一个String扩展,其中包括: 1. 一个属性,返回字符串中每个字符的Ascii值。 2. 一个哈希方法,返回哈希值(复制Java代码)。

extension String {
    var asciiArray: [UInt32] {
        return unicodeScalars.filter{$0.isASCII}.map{$0.value}
    }
    func myHash() -> Int {
        var h = 0 as Int!
        for i in 0..<asciiArray.count {
            h = 31*h! + Int(array[i])
        }
        return h!
    }
}

3
Swift有溢出运算符&+&*等,正是为了这个目的而设立的。 - saagarjha
这里有一个在Swift 3中实现Hashable的示例。 - antonio081014
1
使用哈希值的目的是什么?我的观点和@Alexander一样。 - Ahmad F
这就是在Android上的实现方式,我必须复制它。 - Aftab Baig
@AftabBaig 在你的设备上,Int 很可能是 64 位,而 Java 定义 int 为 32 位。尝试使用 Int32 - saagarjha
显示剩余5条评论
2个回答

10

由于该贴仍缺少答案,这里是可用的代码:

1)编写一个扩展程序,将字符的ascii表示映射到int - 我们需要UInt32,因为Java使用32位系统进行哈希,而不是64位。

2)确保我们所表示的字符串仅包含可映射到ASCII的字符

3)现在执行所述的哈希函数

int h = 0;
if (h == 0 && value.length > 0) {
  char val[] = value;
  for (int i = 0; i < value.length; i++) {
    h = 31 * h + val[i];
  }
  hash = h;
}
return h;

因此,我们将获得以下代码片段,可用于您的项目中。

// 1) Here is our Character extension
extension Character {
    var asciiValue: UInt32? {
        return String(self).unicodeScalars.filter{$0.isASCII}.first?.value
    }
}

extension String {
    // 2) ascii array to map our string
    var asciiArray: [UInt32] {
        return unicodeScalars.filter{$0.isASCII}.map{$0.value}
    }

    // this is our hashCode function, which produces equal output to the Java or Android hash function
    func hashCode() -> Int32 {
        var h : Int32 = 0
        for i in self.asciiArray {
            h = 31 &* h &+ Int32(i) // Be aware of overflow operators, 
        }
        return h
    }
}

2

默认情况下,Swift在整数溢出时会抛出异常(不像C或标准Java整数操作)。为了避免抛出异常,您必须使用提供的特殊函数,例如'addWithOverflow'。

或者,您可以使用-Ounchecked标志进行构建。


1
-Ounchecked 标志禁用的检查远不止溢出检查(例如,数组越界等)。 - saagarjha
1
@SaagarJha 是的,我同意这是不可取的。而且,既然我们谈到了不明智的话题,试图复制本地字符串哈希也可能只会以泪水告终。 - Oscar
看起来他们正在尝试在iOS和Android之间保持一致的哈希值。 - saagarjha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接