使简单元组符合 Hashable,因此可以是 Dictionary Key

Make simple tuple conform to Hashable, so can be a Dictionary Key

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

(Int, Int)

字典键需要是可哈希的。我学会了。

但找不到我如何使这个简单的元组可哈希,并且在最好的时候确实在协议一致性方面遇到困难。

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

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

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

对于class、结构或枚举来说,符合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")

由于CGPoint包含CGFloat值,因此,CGPoint作为Dictionary的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")

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