hashValue란?hashValue는 어떤 객체를 빠르게 식별할 수 있도록 만들어주는 고유한 정수값이다.
객체가 Hashable을 채택하면 자동으로 사용할 수 있게 된다.
예를 들어서:
struct Person: Hashable {
let name: String
let age: Int
}
let foo = Person(name: "Foo", age: 30)
print(foo.hashValue) // 고유한 정수값 출력
이 값은 주로 Set이나 Dictionary처럼 해시 기반 컬렉션에서 빠른 검색을 위해 쓰인다.
정리하자면:
hashValue는 객체를 빠르게 찾기 위한 식별 번호다.
아니다.
두 객체의 hashValue가 같아도 == 비교 결과는 다를 수 있다.
하지만 중요한 규칙이 하나 있다.
==가true라면, 반드시hashValue도 같아야 한다.
이건 Hashable을 제대로 구현하기 위한 필수 조건이다.
struct House: Hashable {
let number: Int
let numberOfBedrooms: Int
}
let house1 = House(number: 123, numberOfBedrooms: 2)
let house2 = House(number: 123, numberOfBedrooms: 2)
print(house1 == house2) // true
print(house1.hashValue == house2.hashValue) // true
왜 같을까?
Swift는 struct가 Hashable을 채택하면, 내부 속성 기준으로 ==와 hashValue를 자동으로 만들어준다.
즉, number와 numberOfBedrooms가 같으니까 둘 다 true가 되는 것.
이번엔 우리가 hash(into:)와 ==을 직접 정의해보자.
struct NumberedHouse: Hashable {
let number: Int
let numberOfBedrooms: Int
func hash(into hasher: inout Hasher) {
hasher.combine(number)
}
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.number == rhs.number
}
}
이렇게 되면 오직 number만을 기준으로 동등성과 해시가 판단된다.
let h1 = NumberedHouse(number: 123, numberOfBedrooms: 2)
let h2 = NumberedHouse(number: 123, numberOfBedrooms: 100)
let set = Set([h1, h2])
print(set.count) // 1
침실 수가 달라도 번호가 같으면 같은 객체로 취급된다.
Set은 중복을 허용하지 않으니까 하나만 들어가는 것.
Set에 넣을 때 내부적으로 어떤 일이 일어날까?Swift는 Set, Dictionary 등에 값을 넣을 때 자동으로 다음을 수행한다.
hash(into:)를 호출해서 해시값 계산==로 진짜 같은지 비교즉, 우리는 함수만 정의하면 되고 언제 호출할지는 Swift가 알아서 처리해준다.
| 상황 | 호출되는 함수 |
|---|---|
a == b | == |
Set.contains(a) | hash(into:) → == (필요시) |
Set.insert(a) | hash(into:) → == (필요시) |
Dictionary[key] = value | hash(into:) → == |
hashValue는 빠른 탐색용 정수값,==는 논리적 동등성 비교. 둘은 짝궁처럼 같이 작동해야 한다.
hashValue보다 hash(into:) 구현이 권장된다.==가 true면 반드시 해시도 같아야 한다 (반대는 아님).Set, Dictionary에서 Hashable을 잘못 구현하면 중복 탐지 실패나 검색 오류 같은 버그가 생길 수 있다.