Swift结构类型集

时间:2016-08-22 12:07:49

标签: swift struct set

说我有一个struct,可能是任何东西:

struct Cube {
    var x: Int
    var y: Int
    var z: Int
    var width: Int
    // ...
}

如何创建这些点的Set,这样就不会有两个具有相同属性的对象?

let points: Set<Cube> = Set()
// Type ‘Cube’ does not conform to protocol ‘Hashable’

但是如何实现hashable并不是很明显。根据我的阅读,我需要创建一个哈希函数,但是在结构中我拥有的属性数量看起来并不容易。

2 个答案:

答案 0 :(得分:15)

首先,Hashable扩展Equatable,因此您必须实施 一个==运算符,使用所有属性比较两个值 哪个唯一标识一个立方体:

func ==(lhs: Cube, rhs: Cube) -> Bool {
    return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.width == rhs.width
}

Hashable协议需要

  

x == y暗示x.hashValue == y.hashValue

所以

var hashValue: Int {
    return 0
}

将是一个有效(和工作)的实现。但是,这会 将所有对象放在集合(或字典)的相同散列桶中, 这是无效的。更好的实现是例如

struct Cube: Hashable {
    var x: Int
    var y: Int
    var z: Int
    var width: Int

    var hashValue: Int {
        return x.hashValue ^ y.hashValue ^ z.hashValue ^ width.hashValue
    }
}

这里&#34; XOR&#34;选择运算符^是因为它不会溢出。 您也可以使用&#34;溢出运算符&#34; &+

更复杂的哈希函数能够区分 不同的值更好,以便设置操作变得更快。 另一方面,哈希函数本身的计算 会慢一些因此,我会寻找一个更好的&#34;哈希函数 只有当设定的操作成为程序中的性能瓶颈时才会出现。

更新: Swift 4.1(Xcode 9.4)开始,编译器可以合成 如果结构的所有成员都是==hashValue方法 Equatable/Hashable。因此,足以声明一致性:

struct Cube: Hashable {
    var x: Int
    var y: Int
    var z: Int
    var width: Int
}

答案 1 :(得分:8)

实施Hashable协议包含两件事。首先是实现hashValue,第二个是实现相等运算符。

让工作Hashable协议的重要部分是相等运算符。它必须以仅返回true的方式实现,并且只有当两个结构包含相同的值时才会实现。

另一方面,只要相同的结构始终返回相同的值,您的hashValue实现就可以返回任何内容。

hashValue影响的唯一因素是代码的运行速度,因为当您添加或查找值时,首先运行的代码为hashValue。如果hashValue为两个结构返回相同的值,则它们之间的相等性将通过调用否则将被跳过的相等运算符来确定。

struct Cube: Hashable {

    // satisfy Hashable requirement
    var hashValue: Int {
        get {
            // you can return any integer here
            return x &+ y &+ z &+...
            // or even the same one for all structs
            return 0
        }
    }
}

// satisfy Equatable requirement
func ==(lhs: Cube, rhs: Cube) -> Bool {
    return lhs.x == rhs.x && lhs.y == rhs.y .....
}