Go에서 구조체 map과 slice는 복사 및 메모리 작업의 중요한 특징을 가지고 있으며, 이는 종종 경험이 부족한 개발자들에게 예기치 않은 행동을 초래합니다.
Go는 정적 타이핑을 가진 엄격한 언어로 간주되며 기본적으로 포인터가 없으나, map과 slice에는 특별한 내부 모델이 구현되어 있습니다: 두 타입 모두 참조 구조입니다. 이로 인해 이러한 객체를 복사하고 전달할 때 여러 가지 nuance가 생기고 제한 사항이 생깁니다.
map과 slice를 복사하면 내용의 깊은 복사가 이루어지지 않고 동일한 객체에 대한 새 링크가 생성되어, 데이터 변경, 함수에서 잘못된 값 반환 및 수정 시 예상치 못한 부작용이 발생합니다. 또한, 함수의 결과로 map 또는 slice를 반환하면 추가 할당이나 메모리 누수가 발생할 수 있습니다.
b := a[:])으로 생성된 경우입니다. 요소를 완전히 복사하려면 내장 함수 copy()를 사용해야 합니다.올바른 복사 예:
// 슬라이스 복사 a := []int{1, 2, 3} b := make([]int, len(a)) copy(b, a) // b는 이제 a와 독립적입니다. // map 복사 src := map[string]int{"x": 1} dst := make(map[string]int) for k, v := range src { dst[k] = v }
주요 특징:
slice와 map은 참조 타입이며, 내용이 아닌 서술자로 복사됩니다.하나의 map/slice를 다른 것으로 단순히 할당한 후 하나를 수정하면 어떻게 될까요?
map과 slice는 동일한 메모리의 데이터를 가리키게 되며, 변경 사항은 두 객체 모두에 영향을 미칩니다.
함수에서 slice나 map을 반환할 때 "메모리 효율적"이라고 자주 말하는 이유는 무엇인가요?
서술자의 복사본이 반환되며 전체 내용이 아닌, 힙에 있는 데이터는 여전히 참조가 있는 한 살아 있습니다.
copy() 함수를 사용하여 map의 "깊은" 복사가 가능한가요?
아니오, copy()는 슬라이스와 배열에만 작동하며, map의 경우 항상 루프가 필요합니다.
개발자는 slice나 map을 할당으로 복사하고 부작용 방지 위해 복사본을 변경합니다:
장점:
단점:
필요한 데이터를 수정하기 전에 slice의 copy()와 map의 루프를 사용합니다:
장점:
단점: