Go에서 map 구조체는 항상 값으로 전달되지만, 이 값은 map 자체의 내부 구조체에 대한 포인터를 포함합니다(내부적으로는 해시 테이블). 따라서 함수를 통해 map을 전달하고 함수 내에서 내용을 변경하면(요소를 추가/삭제), 외부에서 변경 사항을 볼 수 있습니다. slice의 경우도 마찬가지로 동작합니다 — slice 구조체는 복사되지만 원본 배열 데이터는 복사되지 않습니다: slice는 배열에 대한 포인터, 길이 및 용량을 포함합니다. 함수 내에서 인덱스를 통해 값을 변경하면 원본 배열 역시 변경됩니다. 그러나 함수 내에서 새로운 slice를 할당하면(예: reslice) 원본 변수는 변경되지 않습니다.
func updateMap(m map[string]int) { m["key"] = 42 // 변경 사항이 외부에 보입니다! } func updateSlice(s []int) { s[0] = 99 // 원본 배열이 변경됩니다 }
왜 map과 slice를 함수에 전달할 때 함수 내에서의 변경이 "원본"에 반영되나요?
답변: 포인터 구조체만 복사되고 실제 데이터는 공유되므로 — 어떠한 변경이든 동일한 메모리 블록에 영향을 미칩니다.
이야기
핀테크 프로젝트에서 다양한 서비스에 설정 구성을 위한 map을 전달했으며, 로컬 변경이 전체 map에 영향을 미치지 않을 것이라고 생각했습니다. 그 결과, 하나의 서비스가 값을 변경했고, 이는 예상치 못한 수정된 구성을 받은 다른 모듈에서 버그를 초래했습니다.
이야기
분석 마이크로서비스에서 독립적인 복사본을 얻을 수 있을 것으로 예상하고 slice를 전달했습니다. 하지만, 함수 내에서 인덱스의 값을 변경하여 원본 배열이 예상치 않게 변경되면서 보고서의 데이터 왜곡이 발생했습니다.
이야기
게임 서버에서 사용자 세션 저장을 위해 map을 사용하고 이 map을 여러 고루틴에 동시에 전달했습니다. 각 고루틴이 자신의 복사본에서 작업한다고 가정했지만, 실제로 데이터 경쟁이 발생하고 일부 세션이 손실되었습니다.