Como comparar tipos personalizados utilizando o protocol Hashable

Bruno Fernandes
2 min readNov 11, 2016

O que é um protocol Hashable?

Um tipo que fornece um valor inteiro.

Você pode usar qualquer tipo que esteja em conformidade com o protocolo Hashable em um conjunto ou como uma chave de dicionário. Muitos tipos na biblioteca padrão estão em conformidade com Hashable: strings, integers, floats e valores booleanos, e mesmo conjuntos, fornecem um valor hash por padrão. Seus próprios tipos personalizados podem ser hashable também. Quando você define uma enumeração sem valores associados, ganha conformidade Hashable automaticamente e você pode adicionar conformidade Hashable aos seus outros tipos personalizados, adicionando uma única propriedade hashValue.

Um valor de hash, fornecido pelo tipo propriedade hashValue, é um inteiro que é o mesmo para quaisquer das duas instâncias que se comparam igualmente. Ou seja, para duas instâncias a e b do mesmo tipo, se a == b então a.hashValue == b.hashValue. O inverso não é verdade, duas instâncias com valores de hash iguais não são necessariamente iguais entre si. — Apple Developer

Na prática

Entendendo sobre isso, vamos criar uma situação para ver em ação o protocol Hashable. Vamos definir um Array de Strings:

let a = [“four”,”one”, “two”, “one”, “three”,”four”, “four”]

Vamos implementar uma função que irá realizar um filtro e mostrar apenas os registros únicos.

func unique<S: Sequence, E: Hashable>(_ source: S) -> [E] where E==S.Iterator.Element {
var seen: [E:Bool] = [:]
return source.filter {
seen.updateValue(true, forKey: $0) == nil
}
}

A função acima recebe uma sequencia qualquer desde que os elementos da sequencia estejam em conformidade com o protocol Hashable, e então utilizamos um filtro para retornar os valores únicos.

unique(a) // ["four", "one", "two", "three"]

Achou fácil? E se fosse um tipo personalizado, como ficaria? Neste caso precisamos implementar o protocol Hashable e isso não tem segredo, vamos ver na prática criando uma struct Person.

struct Person {
var name: String
var age: Int
}

Para usar seu próprio tipo personalizado em um conjunto ou como o tipo de chave de um dicionário, adicione conformidade Hashable ao seu tipo fornecendo uma propriedade hashValue. O protocolo Hashable herda do protocolo Equatable, então você também deve adicionar uma função de operador igual (==) para seu tipo personalizado.

extension Person: Hashable {
var hashValue: Int {
get {
return name.hashValue ^ age.hashValue
}
}
static func ==(l: Person, r: Person) -> Bool {
return l.hashValue == r.hashValue
}
}

A propriedade hashValue neste exemplo combina os valores hash dos valores name e age de uma Person usando o operador XOR bit a bit (^). O operador ^ é uma maneira de combinar dois valores inteiros em um único valor.

let p = [Person(name: "Jack", age: 22),
Person(name: "Anne", age: 26),
Person(name: "Mary", age: 27),
Person(name: "Anne", age: 26)]
unique(p) // ["Jack", "Anne", "Mary"]

E agora conseguimos comparar, filtrar e realizar diversas operações com tipos personalizados de uma maneira fácil e prática.

O código esta disponível no Github :

--

--