본문 바로가기
프로그래밍/Golang

Golang map(맵) : 기본개념

by slowin 2024. 8. 1.

개요

Go maps in action 의 내용을 참고해서, Golang map기본 개념에 대해서 알아보겠습니다.

1. 기본 구조와 선언

1.1 map(맵)의 기본 구조

map[타입]값

map[KeyType]ValueType

  • 타입: 비교 가능한 모든 타입이 올 수 있습니다.
  • 값: 어떤 타입이든 올 수 있으며, 다른 맵도 포함될 수 있습니다.

1.2 map(맵) 변수 선언

문자열 키와 정수 값을 가지는 맵 변수를 선언하고 싶다면, 다음과 같이 표현 할 수 있습니다.
 

var m map[string]int

1.3 map(맵)의 특성

  • map(맵)은 포인터나 슬라이스와 같은 참조 타입입니다.
  • 위와 같이 선언만 한 맵 m의 값은 nil입니다.
  • nil 맵은 읽을 때는 빈 맵처럼 동작하지만, 쓰기를 시도하면 런타임 패닉이 발생합니다.

1.4 map(맵) 초기화

map(맵)을 안전하게 사용하려면 반드시 초기화해야 합니다. 초기화에는 make 함수를 사용합니다.

m = make(map[string]int)

 
용량을 지정한 초기화

m := make(map[string]int, 100)  // 초기 용량 100으로 설정

2. map(맵) 조작

2.1 map(맵)에 데이터 추가하기

map(맵)에 새로운 키-값 쌍을 추가하는 것은 간단합니다.

m["age"] = 99

2.2 map(맵)에서 데이터 검색하기

i := m["age"]
// 만약 "age" 키가 없다면, i == 0 (int 타입의 제로값)
키 존재 여부 확인과 함께 검색하고 싶을경우,
v, exists := m["age"]

 

  • v: 키에 해당하는 값 (키가 없으면 제로값)
  • exists: 키의 존재 여부를 나타내는 불리언 값 (있으면 true, 없으면 false)

예를들면,

m := map[string]int{"a": 0, "b": 1}

v1, exists1 := m["a"]
fmt.Printf("키 'a': 값 = %d, 존재 여부 = %v\n", v1, exists1)
// 출력: 키 'a': 값 = 0, 존재 여부 = true

v2, exists2 := m["c"]
fmt.Printf("키 'c': 값 = %d, 존재 여부 = %v\n", v2, exists2)
// 출력: 키 'c': 값 = 0, 존재 여부 = false

2.3 map(맵)의 크기 확인하기

내장 함수 len을 사용하여 map(맵)의 length를 확인할수 있습니다.

n := len(m)

 

2.4 map(맵)에서 항목 삭제하기

delete(m, "c")

delete 함수는 아무것도 반환하지 않으며, 지정된 키가 존재하지 않아도 오류를 발생시키지 않습니다.
 

2.5 map(맵) loop

for key, value := range m {
    fmt.Println("Key:", key, "Value:", value)
}

 

3. 심화

3.1 map(맵)을 이용한 집합(Set) 구현

type void struct{}
var member void

set := make(map[string]void)
set["apple"] = member
set["banana"] = member

// 원소 존재 여부 확인
_, exists := set["apple"]
fmt.Printf("'apple'이 집합에 존재하나요? %v\n", exists)

3.2 중첩된 map(맵)

nestedMap := map[string]map[string]int{
    "fruits": {
        "apple":  5,
        "banana": 3,
    },
    "vegetables": {
        "carrot": 7,
        "tomato": 4,
    },
}

fmt.Printf("사과의 개수: %d\n", nestedMap["fruits"]["apple"])

3.3 map(맵)의 동시성 처리

sync.Map을 활용

import "sync"

var m sync.Map

// 저장
m.Store("key", "value")

// 검색
value, ok := m.Load("key")
if ok {
    fmt.Printf("값: %v\n", value)
}

// 삭제
m.Delete("key")

// 순회
m.Range(func(key, value interface{}) bool {
    fmt.Printf("키: %v, 값: %v\n", key, value)
    return true
})

 

sync.RWMutex를 활용

var counter = struct{
    sync.RWMutex
    m map[string]int
}{m: make(map[string]int)}

// 읽기
counter.RLock()
n := counter.m["some_key"]
counter.RUnlock()

// 쓰기
counter.Lock()
counter.m["some_key"]++
counter.Unlock()

3.4 map(맵) 복사

original := map[string]int{"a": 1, "b": 2}
copied := make(map[string]int, len(original))

for k, v := range original {
    copied[k] = v
}

 
 

참고

Go maps in action