Golang의 깊은 복사: 기술소개 및 최상의 관행
James Reed
Infrastructure Engineer · Leapcell

Key Takeaways
- Go에서 깊은 복사는 공유 데이터에 대한 의도치 않은 수정 방지를 위해 필수적입니다.
- 슬라이스, 맵, 그리고 참조 타입이 있는 구조체는 명시적인 깊은 복사가 필요합니다.
copier
와 같은 타사 라이브러리는 깊은 복사 작업을 간소화할 수 있습니다.
소프트웨어 개발에서 데이터 구조의 복사본을 생성하는 것은 흔한 요구 사항입니다. Go(Golang)에서 깊은 복사를 수행하는 방법을 이해하는 것은 하나의 데이터 구조에 대한 수정이 다른 데이터 구조에 예기치 않게 영향을 미치지 않도록 하는 데 필수적입니다. 이 기사에서는 Go에서 깊은 복사를 달성하는 다양한 방법을 살펴봅니다.
얕은 복사 vs. 깊은 복사 이해
깊은 복사 기술을 살펴보기 전에 얕은 복사와 깊은 복사를 구별하는 것이 중요합니다.
-
얕은 복사: 원본과 동일한 기본 데이터를 참조하는 새 변수를 만듭니다. 데이터 변경은 원본과 복사본 모두에 영향을 미칩니다.
-
깊은 복사: 데이터의 자체 복사본이 있는 새 변수를 생성합니다. 복사본의 데이터 수정은 원본에 영향을 미치지 않습니다.
기본 타입 깊은 복사
정수, 부동 소수점, 부울 및 문자열과 같은 Go의 기본 타입은 값으로 복사됩니다. 한 변수를 다른 변수에 할당하면 깊은 복사가 생성됩니다.
a := 42 b := a b = 100 // 'a'는 42로 유지, 'b'는 100
이 예에서 a
와 b
는 독립적입니다. b
를 변경해도 a
에 영향을 미치지 않습니다.
복합 타입 깊은 복사
배열, 슬라이스, 맵, 구조체와 같은 복합 타입의 경우 깊은 복사에 더 많은 주의가 필요합니다.
배열
배열은 Go에서 값 타입입니다. 하나의 배열을 다른 배열에 할당하면 깊은 복사가 수행됩니다.
arr1 := [3]int{1, 2, 3} arr2 := arr1 arr2[0] = 10 // 'arr1'은 [1, 2, 3]으로 유지, 'arr2'는 [10, 2, 3]
슬라이스
슬라이스는 참조 타입입니다. 간단한 할당은 슬라이스 헤더를 복사하지만 기본 데이터는 복사하지 않습니다.
slice1 := []int{1, 2, 3} slice2 := slice1 slice2[0] = 10 // 'slice1'과 'slice2' 모두 [10, 2, 3]
슬라이스를 깊게 복사하려면 기본 데이터를 복사해야 합니다.
slice1 := []int{1, 2, 3} slice2 := make([]int, len(slice1)) copy(slice2, slice1) slice2[0] = 10 // 'slice1'은 [1, 2, 3], 'slice2'는 [10, 2, 3]
맵
맵 또한 참조 타입입니다. 직접 할당은 동일한 기본 데이터를 공유합니다.
map1 := map[string]int{"a": 1, "b": 2} map2 := map1 map2["a"] = 10 // 'map1'과 'map2' 모두 {"a": 10, "b": 2}
맵을 깊게 복사하려면:
map1 := map[string]int{"a": 1, "b": 2} map2 := make(map[string]int) for k, v := range map1 { map2[k] = v } map2["a"] = 10 // 'map1'은 {"a": 1, "b": 2}, 'map2'는 {"a": 10, "b": 2}
구조체
구조체는 값 타입입니다. 하나의 구조체를 다른 구조체에 할당하면 데이터가 복사됩니다.
type Point struct { X, Y int } p1 := Point{1, 2} p2 := p1 p2.X = 10 // 'p1'은 {1, 2}, 'p2'는 {10, 2}
그러나 구조체에 참조 타입(예: 슬라이스, 맵, 포인터)이 포함된 경우 해당 필드를 수동으로 깊게 복사해야 합니다.
타사 라이브러리 사용
복잡한 데이터 구조의 경우 깊은 복사 로직을 수동으로 구현하면 오류가 발생하기 쉽습니다. copier와 같은 타사 라이브러리는 프로세스를 간소화할 수 있습니다.
import "github.com/jinzhu/copier" type Person struct { Name string Age int Friends []string } p1 := Person{Name: "Alice", Age: 30, Friends: []string{"Bob", "Charlie"}} var p2 Person copier.Copy(&p2, &p1) p2.Friends[0] = "David" // 'p1.Friends'는 ["Bob", "Charlie"], 'p2.Friends'는 ["David", "Charlie"]
특히 중첩되거나 복잡한 타입의 경우 라이브러리가 깊은 복사를 수행하는 방법을 이해해야 합니다.
결론
Go에서 깊은 복사를 하려면 관련된 데이터 타입을 신중하게 고려해야 합니다. 기본 타입은 간단하지만 복합 타입은 진정한 깊은 복사를 보장하기 위해 명시적인 처리가 필요합니다. 타사 라이브러리를 활용하면 복잡한 구조를 관리하는 데 도움이 될 수 있지만 항상 해당 동작이 애플리케이션의 요구 사항과 일치하는지 확인하세요.
FAQs
슬라이스와 맵은 참조 타입이므로 할당은 기본 데이터가 아닌 참조만 복사합니다.
새 슬라이스를 수동으로 할당하고 각 요소를 복사하여 진정한 깊은 복사를 보장합니다.
수동으로 깊은 복사를 하기가 어려운 복잡한 중첩 구조를 다룰 때.
Go 프로젝트 호스팅을 위한 최고의 선택, Leapcell입니다.
Leapcell은 웹 호스팅, 비동기 작업 및 Redis를 위한 차세대 서버리스 플랫폼입니다.
다국어 지원
- Node.js, Python, Go 또는 Rust로 개발하세요.
무료로 무제한 프로젝트 배포
- 사용량에 대해서만 지불하세요. 요청도 없고 요금도 없습니다.
탁월한 비용 효율성
- 유휴 요금 없이 사용한 만큼만 지불하세요.
- 예: $25로 평균 응답 시간 60ms에서 694만 건의 요청을 지원합니다.
간소화된 개발자 경험
- 간편한 설정을 위한 직관적인 UI.
- 완전 자동화된 CI/CD 파이프라인 및 GitOps 통합.
- 실행 가능한 통찰력을 위한 실시간 메트릭 및 로깅.
간편한 확장성과 고성능
- 고도의 동시성을 쉽게 처리하기 위한 자동 확장.
- 운영 오버헤드가 없어 구축에만 집중할 수 있습니다.
설명서에서 자세히 알아보세요!
X에서 팔로우하세요: @LeapcellHQ