
์๊ฐ
Go์ map์ ๋งค์ฐ ์ค์ํ ๋ด์ฅ ์๋ฃ๊ตฌ์กฐ๋ก, key-value ํํ์ ํด์ ํ ์ด๋ธ(hash table) ๊ธฐ๋ฐ ์ปจํ ์ด๋์ ๋๋ค.
์๋ฆฌ (๋ด๋ถ ๊ตฌ์กฐ)
Go์ map์ hash table์ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌํ๋์ด ์์ต๋๋ค.
ํต์ฌ ๊ฐ๋
- Key → Hashing → Bucket → Value
- ํด์ ํจ์(hash(key))๋ฅผ ํตํด ๋ฒํท(bucket) ์ธ๋ฑ์ค๋ฅผ ๊ณ์ฐํ๊ณ , ๊ทธ ๋ฒํท์ key-value ์์ ์ ์ฅํฉ๋๋ค.
- ํด์ ์ถฉ๋์ด ๋ฐ์ํ๋ฉด ๊ฐ์ ๋ฒํท ์์ ์ฌ๋กฏ์ ์ฒด์ด๋(chaining) ํํ๋ก ์ ์ฅํฉ๋๋ค.
๋ด๋ถ ๊ตฌ์กฐ ๊ฐ์
Go ๋ฐํ์์์ map์ ๋ค์๊ณผ ๊ฐ์ ๊ตฌ์กฐ๋ก ๊ด๋ฆฌ๋ฉ๋๋ค (runtime/map.go ์ฐธ๊ณ ):
type hmap struct {
count int // ์์ ๊ฐ์
flags uint8
B uint8 // ๋ฒํท ์ = 2^B
buckets unsafe.Pointer // ์ค์ ๋ฐ์ดํฐ ์ ์ฅ์
oldbuckets unsafe.Pointer // ๋ฆฌ์ฌ์ด์ง ์ค์ธ ๋ฒํท
...
}
- ๋ฒํท ์(bucket count): 2^B
- ๋ฆฌ์ฌ์ด์ง(resize): ์์๊ฐ ๋ง์์ง๋ฉด ์๋์ผ๋ก ๋ฒํท ํฌ๊ธฐ๊ฐ 2๋ฐฐ๊ฐ ๋ฉ๋๋ค.
- Load factor (ํ๊ท ๋ฒํท๋น ์์ ์)๊ฐ ์ผ์ ๊ธฐ์ค ์ด์์ด๋ฉด ์ฌ๋ฐฐ์ด(rehashing) ์ํ.
์ฌ์ฉ๋ฒ
๊ธฐ๋ณธ ์ ์ธ ๋ฐ ์ด๊ธฐํ
// ๋น ๋งต ์ ์ธ
var m map[string]int // nil ์ํ, ๋ฐ๋ก ์ฌ์ฉ ๋ถ๊ฐ
// make๋ฅผ ์ฌ์ฉํ ์ด๊ธฐํ
m = make(map[string]int)
// ๋๋ ํ ์ค ์ด๊ธฐํ
m := map[string]int{
"apple": 3,
"banana": 5,
}
์ฝ์ (Insert / Update)
m["apple"] = 10 // ์ถ๊ฐ ๋๋ ์์
์กฐํ (Lookup)
val := m["apple"] // ์กด์ฌํ์ง ์์ผ๋ฉด 0 (int์ zero value)
val, ok := m["apple"] // ok == true์ด๋ฉด ์กด์ฌ
์ญ์ (Delete)
delete(m, "apple")
์ํ (Iteration)
for key, value := range m {
fmt.Println(key, value)
}
Go์ map์ iteration ์์๊ฐ ๋งค๋ฒ ๋๋ค(randomized) ์ ๋๋ค. ๋ณด์์ฑ๊ณผ ํด์ ๊ณต๊ฒฉ ๋ฐฉ์ง๋ฅผ ์ํด ์ค๊ณ์ ์์๊ฐ ๋ณด์ฅ๋์ง ์์ต๋๋ค.
์ฑ๋ฅ ๋ฐ ๋์ ํน์ฑ
์ฅ์
- ํ๊ท ์ ๊ทผ ์๊ฐ O(1)
- ํด์ ๊ธฐ๋ฐ์ด๋ผ ๋น ๋ฅด๊ณ ํจ์จ์
- ํค ํ์ ์ผ๋ก comparableํ ํ์ ์ฌ์ฉ ๊ฐ๋ฅ (== ๋น๊ต ๊ฐ๋ฅํ ํ์ )
์ฃผ์์ฌํญ
- Concurrent access ๊ธ์ง
- ์ฌ๋ฌ ๊ณ ๋ฃจํด์ด ๋์์ ์ฝ๊ธฐ/์ฐ๊ธฐ ํ๋ฉด fatal error: concurrent map read and map write
- ํด๊ฒฐ ๋ฐฉ๋ฒ: sync.Mutex ๋๋ sync.RWMutex๋ก ๋ณดํธํ๊ฑฐ๋, sync.Map ์ฌ์ฉ
var mu sync.RWMutex mu.Lock() m["x"] = 1 mu.Unlock() - Nil map ์ฃผ์
- var m map[string]int m["a"] = 1 // panic! (nil map์ ํ ๋น ๋ถ๊ฐ)
- ์์ ๋ณด์ฅ X
- ์ถ๋ ฅ ์์๊ฐ ๋งค๋ฒ ๋ค๋ฆ → ์์๋ฅผ ์ํ๋ค๋ฉด slice๋ก key๋ฅผ ์ ๋ ฌํด์ผ ํจ.
์์ : ๋น๋ ์นด์ดํธ
func main() {
words := []string{"apple", "banana", "apple", "orange", "banana"}
freq := make(map[string]int)
for _, w := range words {
freq[w]++ // ์กด์ฌํ์ง ์์ผ๋ฉด 0์์ ์์
}
for k, v := range freq {
fmt.Printf("%s: %d\\n", k, v)
}
}
๊ด๋ จ ๊ฐ๋ ์ถ์ฒ
- sync.Map: concurrent-safe map (lock-free, atomic ์ ๊ทผ ์ง์)
- map[string]interface{}: JSON ํ์ฑ ์ ์์ฃผ ์ฌ์ฉ
- struct{}: value๋ฅผ ๋น ๊ตฌ์กฐ์ฒด๋ก ๋์ด set์ฒ๋ผ ์ฌ์ฉ ๊ฐ๋ฅ
set := make(map[string]struct{})
set["A"] = struct{}{}
if _, ok := set["A"]; ok { fmt.Println("exists") }
Go์ map์ ํด์ ๊ธฐ๋ฐ์ ํค-๊ฐ ์๋ฃ๊ตฌ์กฐ๋ก, ํ๊ท ์ ๊ทผ ์๊ฐ์ O(1), ๋ด๋ถ์ ์ผ๋ก ๋ฒํท ๋ฆฌ์ฌ์ด์ง๊ณผ ํด์ ๋ถ์ฐ์ ํตํด ์์ ์ ์ธ ์ฑ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ๋ค๋ง, ๋์์ฑ ์ ์ด์ ์์ ๋น๋ณด์ฅ์ ๋ฐ๋์ ์ฃผ์ํด์ผ ํฉ๋๋ค.
'ํ๋ก๊ทธ๋๋ฐ ์ธ์ด > Go' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [Go] ์ผ์ ์๊ฐ๋ง๋ค ์ค์ผ์ค๋ฌ ๋์ํ๊ธฐ(Ticker) (0) | 2025.11.07 |
|---|---|
| [Go] ํ์์ง์ ์ Format ์ ๋ฆฌ(%v,%s,%d ๋ฑ) (0) | 2025.11.07 |
| [Go] ์ฌ๋ผ์ด์ค(slice)์๋ ํฌ์ธํฐ๊ฐ ์๋ค (0) | 2025.10.14 |
| [Go] ๊ณ ๋ฃจํด(Goroutine) (0) | 2025.10.13 |
| [Go] Gin ํ๋ ์์ํฌ (1) | 2025.09.20 |
๋๊ธ