2016-12-21 6 views
3

Я хотел бы использовать очень простой кортеж в качестве ключа:сделать простой кортеж соответствовать Hashable, поэтому может быть словарь Key

(Int, Int) 

словарь ключи должны быть Hashable. Я узнал.

Но не могу найти, как я делаю этот простой набор Hashable, и в лучшем случае боюсь с соблюдением протокола.

Более глубоко, CGPoint решит мои проблемы. Он может быть такого формата, но не хешируется.

Возможно ли продлить CGPoint так, что это хешируется? Если да, то как?

EDIT: изображение Int варианта выбора CGPoint.

enter image description here

+0

Связанный: [В Swift я могу использовать кортеж в качестве ключа в словаре?] (Http://stackoverflow.com/q/24131323/2976878) – Hamish

ответ

6

Изготовление соответствует Hashable не трудно класса, структуры или перечисления. Вам просто нужно явно объявить соответствие Hashable и определить свойство hashValue: Int. Практически, hashValue должен выполнить одну простую аксиому: , если a == b затем 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 в качестве ключа словаря может привести к неожиданному поведению, основанному на ошибке вычисления двоичной системы с плавающей запятой. Вы должны использовать его с особой осторожностью.


Сложение

Если вы хотите, чтобы избежать некоторых проблем ошибки вычисления и можете признать, что структура может содержать только 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") 

Не намного сложнее, чем приведенный выше код, еще одна вещь, в которой вы нуждаетесь, - это просто определение оператора для структуры. ==. Пожалуйста, попробуйте.

+0

Отлично. Что такое float, могу ли я использовать вариант CGPoint, основанный на Integer? – Confused

+0

Добавлено изображение на вопрос, так как я не могу добавить комментарий здесь – Confused

+0

Даже если вы используете инициализатор 'CGPoint' с' Int', значения внутренне преобразуются в 'CGFloat'. Если вы имеете в виду свою собственную структуру с вариантом CGPoint_, вы можете это сделать. Вы можете написать что-то вроде 'struct MyPoint: Hashable {...}', просто вам нужно определить как свойство hashValue, так и '=='. – OOPer