3

非常に単純なタプルをキーとして使用したいと思います。

(Int, Int)

辞書のキーは Hashable である必要があります。私は学びました。

しかし、この単純なタプルを Hashable にする方法を見つけることができず、最高の状態でプロトコルの適合性に苦労しています。

もっと深刻なことに、CGPoint は私の問題を解決してくれるでしょう。この形式にすることもできますが、ハッシュ可能ではありません。

ハッシュ可能になるように CGPoint を拡張することは可能ですか? もしそうなら、どのように?

編集: CGPoint 選択の Int バリアントの画像。

ここに画像の説明を入力

4

1 に答える 1

6

Hashableクラス、構造体、または列挙型に適合させることは難しくありません。への準拠を明示的に宣言しHashable、プロパティを定義するだけですhashValue: Int。実際には、a == b then a.hashValue == b.hashValue というhashValue1 つの単純な公理を満たす必要があります。

( に適合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")

asには値CGPointが含まれてCGFloatいるため、CGPointas Dictionary の Key は、2 進浮動小数点システムの計算エラーに基づいて予期しない動作を引き起こす可能性があります。特に注意して使用する必要があります。


添加

計算エラーの問題を回避し、構造体に のみを含めるIntことができる場合は、独自の構造体を定義して、次のように準拠させることができます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")

上記のコードほど難しくはありません。もう 1 つ必要なのは==、構造体の演算子を定義することだけです。ぜひお試しください。

于 2016-12-21T01:16:50.067 に答える