3

我想使用一个非常简单的元组作为键:

(Int, Int)

字典键需要是可散列的。我学会了。

但是找不到我如何制作这个简单的 Hashable 元组,并且在最好的时候确实与协议一致性作斗争。

更深刻的是,CGPoint 可以解决我的问题。它可以是这种格式,但不可散列。

是否可以扩展 CGPoint 使其可散列?如果是这样,怎么做?

编辑: CGPoint 选择的 Int 变体的图像。

在此处输入图像描述

4

1 回答 1

6

对于类、结构或枚举而言,使符合Hashable并不难。您只需要明确声明符合Hashable并定义一个属性hashValue: Int。实际上,hashValue需要满足一个简单的公理:if a == b then a.hashValue == b.hashValue

(要符合Hashable,您还需要创建类型Equatable。如果是CGPoint,它已经是Equatable。)

CGPoint一个符合的例子Hashable

extension CGPoint: Hashable {
    public var hashValue: Int {
        //This expression can be any of the arbitrary expression which fulfills the axiom above.
        return x.hashValue ^ y.hashValue
    }
}

var pointDict: [CGPoint: String] = [
    CGPoint(x: 1.0, y: 2.0): "PointA",
    CGPoint(x: 3.0, y: 4.0): "PointB",
    CGPoint(x: 5.0, y: 6.0): "PointC",
]
print(pointDict[CGPoint(x: 1.0, y: 2.0)]) //->Optional("PointA")

AsCGPoint包含CGFloat值,因此, As CGPointDictionary 的 Key 可能会导致基于二进制浮点系统的计算错误的意外行为。您需要格外小心地使用它。


添加

如果您想避免一些计算错误问题并且可以接受结构只能包含Ints,您可以定义自己的结构并使其符合Hashable

struct MyPoint {
    var x: Int
    var y: Int
}
extension MyPoint: Hashable {
    public var hashValue: Int {
        return x.hashValue ^ y.hashValue
    }

    public static func == (lhs: MyPoint, rhs: MyPoint) -> Bool {
        return lhs.x == rhs.x && lhs.y == rhs.y
    }
}
var myPointDict: [MyPoint: String] = [
    MyPoint(x: 1, y: 2): "MyPointA",
    MyPoint(x: 3, y: 4): "MyPointB",
    MyPoint(x: 5, y: 6): "MyPointC",
]
print(myPointDict[MyPoint(x: 1, y: 2)]) //->Optional("MyPointA")

并不比上面的代码难多少,您还需要做的一件事就是==为结构定义运算符。请尝试一下。

于 2016-12-21T01:16:50.067 回答