Go에서 대부분의 내장 데이터 타입(예: int, float, struct)은 가변적입니다. 변수로 선언되었기 때문에 값으로 전달 시 전체 구조 또는 값이 복사됩니다. 그러나 한 가지 미세한 점이 있습니다: 슬라이스(slice), 맵(map), 채널(channel)은 내부 데이터 저장 로직을 가진 참조 타입입니다.
기본 유형:
x := 10 y := x // 여기서 값의 복사본이 생성되며, x와 y는 서로 연결되지 않음 y = 20 // x는 여전히 10
슬라이스:
a := []int{1,2,3} b := a // 기본 배열의 동일한 '슬라이스'에 대한 참조 b[0] = 100 // 이제 a[0]도 100이 됨
함수나 메서드가 구조체나 슬라이스를 받을 때 중요합니다. 데이터의 변경이 원본 데이터에 영향을 미칠 수 있는지 여부는 데이터 타입과 전송 방식(값에 의한 전송 또는 참조에 의한 전송)에 따라 다릅니다.
질문: "슬라이스를 하나에서 다른 슬라이스에 할당하면, 깊은 복사를 얻습니까, 아니면 두 개가 동일한 데이터에 각각 참조하게 됩니까?"
답변: 슬라이스를 단순히 할당할 경우(b := a), 두 개 모두 동일한 기본 배열을 참조하지만, 길이와 용량은 독립적입니다. 한 슬라이스를 통해 배열 데이터를 수정하는 경우 다른 슬라이스에서 보입니다.
예시:
a := []int{1,2,3} b := a b[0] = 42 fmt.Println(a) // [42 2 3]
깊은 복사를 만들려면 copy를 사용해야 합니다:
c := make([]int, len(a)) copy(c, a) c[0] = 99 fmt.Println(a) // [42 2 3], c는 독립적인 복사본
이야기
데이터 필터링 서비스가 예기치 않은 결과를 반환하기 시작한 이유: 한 개발자가 슬라이스를 여러 함수 간에 복사 없이 전달하여 상태를 변경했습니다. 서로 다른 곳에서 슬라이스가 수정되어 애플리케이션의 논리가 깨지고, 오랜 기간 동안 잡지 못한 데이터의 이상한 버그가 발견되었습니다.
이야기
구조체 전달 후 데이터 손실: 한 프로젝트에서 데이터 직렬화 시 의도치 않게 구조체의 필수 필드를 삭제했습니다. 객체가 참조로 전달되었으므로 복사본이 생성되지 않았고, 이로 인해 운영 중에 중요 정보가 손실되었습니다.
이야기
맵에서의 병렬 작업 오류: 개발자가 맵에 대한 참조를 복사하여 변경이 원본에 영향을 주지 않을 것이라고 생각했습니다. 그로 인해 서로 다른 고루틴에서 데이터 경합이 발생하여 애플리케이션이 충돌했습니다.