Hash: 어떠한 데이터를 고정된 길이와 유일한 값으로 반환 및 매핑해주는 함수, 코드, 체크섬 등을 의미합니다.
HashValue: Hash에 의해 도출되는 값을 의미합니다.
Hashable: 값의 고정된 길이와 유일성을 보장해주는 프로토콜입니다.
Swift에서 Hashable 프로토콜은 값의 고정된 길이와 유일성을 보장하기 위해 만들어진 프로토콜입니다.
Hashable 프로토콜은 Equatable 프로토콜을 상속받기 때문에 Equatable 프로토콜의 요구사항 코드를 작성할 필요가 있습니다. (속성이 Equatable 프로토콜을 채택한 타입이라면 작성할 필요가 없지만, 클래스의 경우에는 꼭 작성해야 합니다.)
Comparable 프로토콜의 요구사항 코드는 아래와 같습니다.
func hash(into hasher: inout Hasher){
hasher.combine(파라미터 이름)
...
}
Swift에서 기본적으로 제공해주는 기본타입(Int, String, Double 등)은 Hashable 프로토콜을 자동으로 채택하고 있습니다. 때문에 고유값(유일값)을 요구하는 Set, Dictionary의 key값으로 사용할 수 있습니다.
var set1: Set = [1,2,3,4]
var set2: Set = ["A","B","C","D"]
var dic1: Dictionary<Int, String> = [1:"A", 2:"B", 3:"C"] // <key, value>
var dic2: Dictionary<String, String> = ["일":"A", "이":"B", "삼":"C"] // <key, value>
하지만 사용자가 정의한 타입 즉, 커스텀 타입(Enum, Struct, Class)의 경우에는 Hashable 프로토콜을 자동으로 채택하지 않음으로 필요에 따라 사용자가 직접 Hashable 프로토콜 채택 및 요구사항 메서드를 구현해야 합니다.
원칙적으로 열거형의 경우에는 Hashable 프로토콜을 채택해야만 고정값과 고유값을 가질 수 있습니다.
하지만 열거형에 연관값이 없다면 열거형은 기본적으로 Equatable/Hashable하기 때문에 별다른 채택 없이 사용 가능합니다. (기본타입의 원시값만 있는 경우에도 별다른 채택 없이 사용 가능합니다.)
✅ 연관값이 없는 경우의 Hashable
enum number{ case one case two case three } var set: Set = [number.one, number.two, number.three]
✅ 기본타입의 원시값이 있는 경우의 Hashable
원시값의 타입이 기본타입(Hashable 프로토콜을 채택한 타입)이라면 Hashable 프로토콜 채택 없이 사용할 수 있습니다.
enum number: Int{ case one case two case three } var set: Set = [number.one, number.two, number.three]
✅ 기본타입의 연관값이 있는 경우의 Hashable
연관값의 타입이 기본타입(Hashable 프로토콜을 채택한 타입)이라면 Hashable 프로토콜만을 채택하여 사용할 수 있습니다 (요구사항 메서드를 작성할 필요가 없음)
enum number: Hashable{ case one(Int) case two(String) case three(Double) } var set: Set = [number.one(1), number.two("이"), number.three(3.0)]
구조체의 모든 저장속성이 Hashable 프로토콜을 채택한 타입이라면 Hash 메서드 구현 없이 바로 사용 가능합니다.
✅ 구조체의 Hashable
struct Man: Hashable{ var name: String var age: Int func hello(){ print("안녕") } } var kim = Man(name: "김철수", age: 25) var shin = Man(name: "신짱구", age: 25) var set: Set = [kim, shin]
클래스의 모든 저장 속성이 Hashable 프로토콜을 채택한 타입이더라도 Hash 메서드를 꼭 구현해야 하며, Hashable 프로토콜이 상속받고 있는 Equatable 프로토콜의 요구사항 메서드 또한 작성해야 합니다.
✅ 클래스의 Hashable
class Man{ var name: String var age: Int init(name: String, age: Int){ self.name = name self.age = age } func hello(){ print("안녕") } } extension Man: Hashable{ static func == (lhs: Man, rhs: Man) -> Bool { // 필수 구현!! return (lhs.name == rhs.name) && (lhs.age == rhs.age) } func hash(into hasher: inout Hasher) { hasher.combine(name) hasher.combine(age) } } var kim = Man(name: "김철수", age: 25) var shin = Man(name: "신짱구", age: 25) var set: Set = [kim, shin]