Hashable - ehrldyd15/Swift_Skills GitHub Wiki
Hashable
1. ํด์(Hash)๋?
ํน์ Key - Value๋ฅผ ์ ์ฅํ๋ค๊ณ ํ๋ฉด
ํด๋น Key๋ฅผ ํด์ ํจ์๋ ๊ฒ์ ํตํด ํด์๋ฅผ ํ๊ณ ,
๊ฒฐ๊ณผ ๊ฐ์ธ ํด์ ์ฃผ์ ๊ฐ์ ํด๋นํ๋ ํด์ ํ ์ด๋ธ ์ฌ๋กฏ์ Value๋ฅผ ์ ์ฅํ๋ ๊ฒ์ด๋ค.

์ฆ, Key ๊ฐ์ ํด์ฑ ํจ์์ ๋ฃ์ด ํด์ ํ์ฌ ๋ฐฐ์ด์ ์ฃผ์๊ฐ(ํด์ ์ฃผ์๊ฐ)์ ์ป๊ณ , ๊ทธ ์ฃผ์๊ฐ์ ๋ง๋ index์ Value๊ฐ์ ์ ์ฅํ๋ ๊ฒ์ด๋ค.
์๋ฅผ ๋ค์ด ์๋์ฒ๋ผ Key๊ฐ์ผ๋ก ๊ธฐ๋ณธ ์๋ฃํ(Int, String)์ ์ธ ๊ฒฝ์ฐ
let myDict: [String: Int] = ["ABC": 28]
Equatable๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๊ธฐ๋ณธ ์๋ฃํ์ ์ปดํ์ผ๋ฌ์ ์ํด Hashable ํ๋กํ ์ฝ์ด ์๋์ผ๋ก ์ฑํ๋๋ค.
๊ทธ๋ฌ๋ ๋ง์ฝ ๊ตฌ์กฐ์ฒด๋ก ๋ง๋ค๊ฒฝ์ฐ
struct Human {
let name: String
let age: Int
}
let myDict: [Human: Int] โ // Type 'Human' does not conform to protocol 'Hashable'
Human ๋ด๋ถ์ name, age๋ ํ๋กํผํฐ๊ฐ ๊ธฐ๋ณธ ์๋ฃํ์ด์ง๋ง,
์ด๋ค ๊ฐ์ผ๋ก ํด์๋ฅผ ํด์ผํ ์ง ๋ชจ๋ฅด๊ธฐ ๋๋ฌธ์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
(Hashable ํ๋กํ ์ฝ์ ์ค์ํ์ง ์์๋ค๋ ์๋ฌ์ด๋ค.)
๋ฐ๋ผ์ ๋์ ๋๋ฆฌ์์ Key๊ฐ์ ๋ฌด์กฐ๊ฑด ์ด๋ค ํ๋กํผํฐ๋ฅผ ํด์ ํ ์ง์ ๋ํด ์ ์ํด์ผํ๋,
๋ฐ๋ก Hashable์ด๋ ํ๋กํ ์ฝ์ ์ค์ํ๊ณ ์๋ ํ์ ๋ง์ด ๊ฐ๋ฅํ ๊ฒ์ด๋ค.
(๋์ ๋๋ฆฌ ๋ฟ๋ง ์๋๋ผ ํด์ ํ ์ด๋ธ์ ์ฐ๋ Set์ ์ธ ๋๋ ๋ง์ฐฌ๊ฐ์ง๋ค.)

Hashable ํ๋กํ ์ฝ์ ์์ ๊ฐ์ด ์๊ฒผ๋ค.
hashValue๋ ๋์ด์ ์ฌ์ฉํ์ง ์๋ ํ๋กํผํฐ๋ผ๊ณ ํ๊ณ ,
ํ์ํ ๊ฒฝ์ฐ hash(into:) ํจ์๋ฅผ ์ง์ ๊ตฌํํด์ฃผ์ด์ผ ํ๋ค.
๋ํ Hashable์ ์์ฒด์ ์ผ๋ก Equatable์ด๋ ํ๋กํ ์ฝ์ ์ค์ํ๊ณ ์๋ค.
2. ๊ตฌ์กฐ์ฒด, ํด๋์ค, ์ด๊ฑฐํ์์ Hashable์ ์ฑํํ๋ ๋ฐฉ๋ฒ
2-1 ๊ตฌ์กฐ์ฒด
Equatable๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ง์ฝ ๊ตฌ์กฐ์ฒด ๋ด ํ๋กํผํฐ๊ฐ ๋ชจ๋ ๊ธฐ๋ณธ ์๋ฃํ์ด๋ผ๋ฉด,
Hashable์ ์ฑํํ๋ ๊ฒ๋ง์ผ๋ก ์ถ๊ฐ ๊ตฌํ ์์ด ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
struct Human: Hashable {
let name: String
let age: Int
}
let myDict: [Human: Int] = [:]
์ด๋ฐ ์์ผ๋ก Human์ด๋ผ๋ ๊ตฌ์กฐ์ฒด๋ฅผ ๋์ ๋๋ฆฌ์ Key๋ก ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
2-2 ํด๋์ค
ํด๋์ค๋ Hashable์ด๋ ํ๋กํ ์ฝ์ ์ค์ํ๋ ๊ฒ ์ธ์๋ ์ง์ hashํจ์๋ฅผ ๊ตฌํํด์ฃผ์ด์ผ ํ๋ค.
๋คํ์ค๋ฝ๊ฒ๋ combine์ด๋ผ๋ ๋ฉ์๋๋ฅผ ํตํ์ฌ ์ฝ๊ฒ ๊ตฌํ์ด ๊ฐ๋ฅํ๋ค.
class Human {
let name = "ABC"
let age = 28
}
extension Human: Hashable {
func hash(into hasher: inout Hasher) {
hasher.combine(name)
hasher.combine(age)
}
}
let myDict: [Human: Int] = [:]
์ด๋ ๊ฒ! hash ๋ฉ์๋๋ฅผ ์ง์ ๊ตฌํํด์ฃผ๋๋ฐ,
์ด๋ hasher.combine์ด๋ ๋ฉ์๋์ ์ด๋ค ํ๋ผ๋ฏธํฐ๋ฅผ ํด์ํ ๊ฒ์ธ์ง๋ฅผ ๋ฃ์ด์ค๋ค.
ํน๋ณํ ๊ฒฝ์ฐ๊ฐ ์๋๋ฉด combine์๋ ํด๋น ํ์
์ ๋ชจ๋ ์ ์ฅ ํ๋กํผํฐ๋ฅผ ์ ๋ฌํ๋ ๊ฒ์ด๋ค.
๋ํ, combine ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌํ๋ ํ๋กํผํฐ๋ ๋ฐ๋์ Hashable์ ์ค์ํ๊ณ ์์ด์ผ ํ๋ค.
(์์์ name, age๋ ๊ธฐ๋ณธ ์๋ฃํ์ด๊ณ , ์๋์ผ๋ก Hashable์ ์ค์ํ๊ณ ์๊ธฐ ๋๋ฌธ์ ์์ฒ๋ผ combine์ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌ ํ ์ ์๋ค.)
๊ทธ๋ฌ๋

์์ ๊ฐ์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
Hashable์ Equatable์ ์ฑํํ๊ณ ์์ด์ ์๋์ผ๋ก ์ ๊ณต๋์ง ์๋ ํด๋์ค์ ๊ฒฝ์ฐ ์ง์ ๊ตฌํ์ด ํ์ํ๊ธฐ ๋๋ฌธ์ด๋ค.
class Human {
let name = "ABC"
let age = 28
}
extension Human: Hashable {
static func == (lhs: Human, rhs: Human) -> Bool {
return lhs.name == rhs.name && lhs.age == rhs.age
}
func hash(into hasher: inout Hasher) {
hasher.combine(name)
hasher.combine(age)
}
}
let myDict: [Human: Int] = [:]
์ด์ ์ผ ๋ณด๋ก์ Human์ด๋ผ๋ ํด๋์ค๋ฅผ Hashable ํ๋กํ ์ฝ์ ์ฑํํด์ผ ํ๋ ์๋ฃํ์์ ์ฌ์ฉํ ์ ์๋ค.
ํด๋์ค์์ Hashable์ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด, hash ๋ฉ์๋๋ฅผ ์ง์ ๊ตฌํ + "==" ๋ฉ์๋ ์ง์ ๊ตฌํ ํด์ผ ํ๋ค.
2-3 ์ด๊ฑฐํ
์ฐ๊ด๊ฐ์ด ์๋ ์ด๊ฑฐํ
enum Gender {
case male
}
let myDict: [Gender: Int] = [:]
Hashable์ ์ฑํํ์ง ์์๋ ์๋์ผ๋ก ๊ตฌํ์ด ๋๋ค.
์ฐ๊ด๊ฐ์ด ์๋ ์ด๊ฑฐํ
enum Gender: Hashable {
case male(age: Int)
}
let myDict: [Gender: Int] = [:]
Hashable์ ์ฑํํ๋ค๊ณ ์ ์ธํด์ฃผ๊ณ ,
์ฐ๊ด๊ฐ์ ํ์ ์ด(Int)์ด ๋ชจ๋ Hashable์ ์ฑํ(๊ตฌํ)ํ๊ณ ์์ด์ผ ํ๋ค.