Golang에서 구조체를 복사하는 방법
Min-jun Kim
Dev Intern · Leapcell

Key Takeaways
- 얕은 복사는 직접 할당을 사용하지만 참조 유형에는 잘 작동하지 않습니다.
- 깊은 복사에는 의도치 않은 수정 방지를 위해 포인터, 슬라이스 및 맵에 대한 수동 할당이 필요합니다.
- JSON 직렬화는 쉬운 깊은 복사 솔루션을 제공하지만 성능 오버헤드가 있습니다.
Golang에서 구조체를 복사하는 것은 데이터를 복제하거나, 의도치 않은 수정을 방지하거나, 동시 작업을 처리하는 등 일반적인 요구 사항입니다. 이 기사에서는 얕은 복사, 깊은 복사, 모범 사례를 포함하여 Go에서 구조체를 복사하는 다양한 방법을 설명합니다.
구조체의 얕은 복사
Go에서 얕은 복사는 원본과 동일한 값을 가진 새 구조체를 만드는 것을 의미합니다. 이는 구조체가 기본 유형 또는 포인터를 포함하지 않는 값만 포함하는 경우에 잘 작동합니다.
할당 사용
구조체를 복사하는 가장 간단한 방법은 직접 할당을 사용하는 것입니다.
package main import "fmt" type Person struct { Name string Age int } func main() { original := Person{Name: "Alice", Age: 30} copy := original // 얕은 복사 copy.Name = "Bob" // 복사본을 수정해도 원본에 영향을 주지 않습니다. fmt.Println("Original:", original) // Output: {Alice 30} fmt.Println("Copy:", copy) // Output: {Bob 30} }
Go는 구조체 변수를 값 유형으로 취급하므로 직접 할당은 메모리에 구조체의 새 복사본을 만듭니다.
구조체의 깊은 복사
깊은 복사는 포인터와 슬라이스를 포함한 모든 필드가 메모리 참조를 공유하지 않고 독립적으로 복사되도록 합니다.
포인터가 있는 구조체 복사
구조체에 포인터 필드가 포함된 경우 직접 할당은 실제 데이터가 아닌 포인터 참조를 복사합니다. 이는 의도치 않은 부작용을 초래할 수 있습니다.
package main import "fmt" type Person struct { Name *string Age int } func deepCopy(p Person) Person { nameCopy := *p.Name // 새 문자열 값을 만들기 위해 역참조 return Person{ Name: &nameCopy, Age: p.Age, } } func main() { name := "Alice" original := Person{Name: &name, Age: 30} copy := deepCopy(original) *copy.Name = "Bob" // 복사본의 이름을 수정해도 원본에 영향을 주지 않습니다. fmt.Println("Original:", *original.Name) // Output: Alice fmt.Println("Copy:", *copy.Name) // Output: Bob }
여기서 새 문자열 변수(nameCopy
)는 원본 구조체를 수정하지 않도록 생성됩니다.
슬라이스 및 맵이 있는 구조체 복사
슬라이스와 맵은 참조 유형입니다. 즉, 할당을 통해 복사하면 깊은 복사본이 생성되지 않습니다. 대신 새 슬라이스 또는 맵을 수동으로 할당하고 각 요소를 복사해야 합니다.
package main import "fmt" type Person struct { Name string Scores []int } func deepCopy(p Person) Person { scoresCopy := make([]int, len(p.Scores)) copy(scoresCopy, p.Scores) // 내장 copy 함수 사용 return Person{ Name: p.Name, Scores: scoresCopy, } } func main() { original := Person{Name: "Alice", Scores: []int{90, 85, 88}} copy := deepCopy(original) copy.Scores[0] = 100 // 복사본을 변경해도 원본에 영향을 주지 않습니다. fmt.Println("Original Scores:", original.Scores) // Output: [90 85 88] fmt.Println("Copy Scores:", copy.Scores) // Output: [100 85 88] }
copy()
함수는 슬라이스 요소를 새 슬라이스에 복사하는 데 사용되어 원본으로부터 독립성을 보장합니다.
JSON 인코딩을 사용하여 구조체 복사
복잡한 구조체의 경우 JSON 직렬화는 깊은 복사를 달성하는 편리한 방법입니다.
package main import ( "encoding/json" "fmt" ) type Person struct { Name string Age int Tags []string } func deepCopy(original Person) Person { var copy Person data, _ := json.Marshal(original) // JSON으로 직렬화 json.Unmarshal(data, ©) // 새 구조체로 역직렬화 return copy } func main() { original := Person{Name: "Alice", Age: 30, Tags: []string{"engineer", "gamer"}} copy := deepCopy(original) copy.Tags[0] = "artist" // 복사본을 수정해도 원본에 영향을 주지 않습니다. fmt.Println("Original Tags:", original.Tags) // Output: [engineer gamer] fmt.Println("Copy Tags:", copy.Tags) // Output: [artist gamer] }
JSON 기반 복사는 쉽지만 몇 가지 단점이 있습니다.
- 성능 오버헤드: 직렬화 및 역직렬화는 수동 복사보다 느릴 수 있습니다.
- 유형 안전성: JSON은
interface{}
또는 함수 포인터와 같은 Go 특정 유형을 보존하지 않습니다.
구조체 복사를 위한 모범 사례
- 단순 구조체에는 직접 할당 사용: 구조체에 값 유형(
int
,float64
또는string
과 같은)만 포함된 경우 직접 할당으로 충분합니다. - 포인터, 슬라이스 및 맵을 수동으로 복사: 의도치 않은 수정을 방지하기 위해 새 할당을 확인합니다.
- 깊은 복사에는
json.Marshal
고려: 복잡한 구조체에 유용하지만 성능 비용이 발생할 수 있습니다. - 대규모 프로젝트에는 깊은 복사 라이브러리 사용:
copier
(https://github.com/jinzhu/copier)와 같은 라이브러리는 깊은 복사를 위한 일반적인 솔루션을 제공합니다.
결론
Go에서 구조체 복사는 얕은 복사가 필요한지 깊은 복사가 필요한지에 따라 다릅니다. 단순 할당은 값 기반 구조체에 적합하고 깊은 복사에는 포인터 기반 및 참조 유형에 대한 수동 할당이 필요합니다. 이러한 기술을 이해하면 일반적인 함정을 피하고 Go 애플리케이션에서 데이터 무결성을 보장하는 데 도움이 됩니다.
FAQs
슬라이스와 맵은 참조 유형이므로 할당은 데이터가 아닌 참조를 복사합니다.
필드를 수동으로 복사하는 것이 가장 빠릅니다. JSON 직렬화는 더 쉽지만 느립니다.
구조체에 포인터, 슬라이스 또는 맵이 포함되어 공유 수정 사항을 방지하려면 깊은 복사를 사용하십시오.
Leapcell은 Go 프로젝트 호스팅을 위한 최고의 선택입니다.
Leapcell은 웹 호스팅, 비동기 작업 및 Redis를 위한 차세대 서버리스 플랫폼입니다.
다국어 지원
- Node.js, Python, Go 또는 Rust로 개발하십시오.
무료로 무제한 프로젝트 배포
- 사용량에 대해서만 비용을 지불하십시오. 요청이나 요금이 없습니다.
탁월한 비용 효율성
- 유휴 요금 없이 사용한 만큼만 지불하십시오.
- 예: $25는 평균 응답 시간 60ms에서 694만 건의 요청을 지원합니다.
간소화된 개발자 경험
- 간편한 설정을 위한 직관적인 UI.
- 완전 자동화된 CI/CD 파이프라인 및 GitOps 통합.
- 실행 가능한 통찰력을 위한 실시간 메트릭 및 로깅.
손쉬운 확장성 및 고성능
- 고도의 동시성을 쉽게 처리하기 위한 자동 확장.
- 운영 오버헤드가 전혀 없습니다. 빌드에만 집중하십시오.
설명서에서 자세히 알아보십시오!
X에서 팔로우하세요: @LeapcellHQ