고(Go) 슬라이스 복사, 이것만 알면 끝! copy와 append 완벽 활용법 (초보자 필독)
슬라이스 복사, 왜 신경 써야 할까요? 핵심은 '참조'의 이해!
고(Go) 언어에서 슬라이스는 데이터를 담는 아주 유용한 도구인데요, 마치 여러 개의 칸을 가진 수납함과 비슷합니다.
그런데 이 슬라이스는 조금 특별한 성질을 가지고 있습니다.
바로 '참조(Reference)'라는 방식으로 작동한다는 점인데요.
쉽게 말해, 슬라이스 변수 자체는 진짜 데이터 덩어리를 직접 들고 있는 게 아니라, 데이터가 실제로 저장된 곳의 '주소'만 가지고 있는 것과 같습니다.
그래서 슬라이스를 단순하게 다른 변수에 할당(=
)해서 복사하려고 하면, 겉보기에는 복사가 된 것 같지만 실제로는 같은 주소를 가리키게 됩니다.
이러면 복사본에서 값을 바꿨는데 원본까지 바뀌어버리는, 마치 마법 같은 (하지만 프로그래머에겐 악몽 같은!) 일이 벌어질 수 있답니다.
따라서 고(Go)에서는 슬라이스를 제대로, 안전하게 복사하는 방법을 아는 것이 매우 중요합니다.
자, 그럼 지금부터 그 방법들을 하나씩 살펴볼까요?.
첫 번째 방법: 똑똑한 내장 함수 copy
활용하기!
고(Go) 언어는 슬라이스를 안전하게 복사할 수 있도록 copy
라는 아주 편리한 내장 함수를 제공합니다.
이 함수는 이름 그대로 원본 슬라이스의 요소들을 새로운 대상 슬라이스로 깔끔하게 복사해주는 역할을 하는데요.
어떻게 사용하는지 예제 코드를 통해 자세히 살펴보겠습니다.
package main
import "fmt"
func main() {
// 복사하고 싶은 원본 슬라이스
original := []int{1, 2, 3, 4, 5}
// 원본 슬라이스와 똑같은 길이로 새로운 슬라이스를 만들어줍니다.
// make 함수는 슬라이스, 맵, 채널 등을 초기화할 때 사용해요.
copySlice := make([]int, len(original))
// copy 함수를 사용해서 original 슬라이스의 내용을 copySlice로 복사합니다.
// 첫 번째 인자가 복사 받을 슬라이스, 두 번째 인자가 원본 슬라이스입니다.
copy(copySlice, original)
// 복사된 슬라이스의 내용을 출력해볼까요?
fmt.Println(copySlice) // 결과: [1 2 3 4 5]
}
위 예제 코드를 자세히 뜯어볼까요?.
- 먼저
original
이라는 이름으로 정수(int)들을 담고 있는 슬라이스를 만들었습니다. - 다음으로,
copySlice
라는 이름의 새로운 슬라이스를 만들었는데요, 이때make
함수와len(original)
을 사용해서 원본 슬라이스와 똑같은 길이로 만들어주는 것이 중요합니다.copy
함수는 복사 받을 슬라이스의 길이만큼만 요소를 복사하기 때문입니다. - 마지막으로
copy(copySlice, original)
코드를 통해original
슬라이스의 요소들을copySlice
로 복사했습니다.
결과적으로 copySlice
는 original
과 똑같은 내용을 가지면서도, 서로 다른 메모리 공간을 사용하는 완전히 독립적인 슬라이스가 되었습니다!
슬라이스의 특정 부분만 쏙 빼서 복사하고 싶다면?
copy
함수는 슬라이스 전체뿐만 아니라, 원하는 부분만 쏙 골라서 복사하는 것도 가능합니다.
예를 들어, 원본 슬라이스의 중간 부분만 복사하고 싶을 때 아주 유용한데요.
package main
import "fmt"
func main() {
// 원본 슬라이스
original := []int{1, 2, 3, 4, 5}
// 원본 슬라이스의 일부분을 담을 새로운 슬라이스를 만듭니다.
// 여기서는 3개의 요소만 복사할 거라 길이를 3으로 지정했어요.
copySlice := make([]int, 3)
// original 슬라이스의 1번 인덱스부터 4번 인덱스 *이전까지* (즉, 1, 2, 3번 인덱스) 요소를 복사합니다.
// 슬라이스[시작인덱스:끝인덱스] 문법에서 끝인덱스는 포함되지 않는다는 점을 기억해주세요!
copy(copySlice, original[1:4])
// 복사된 슬라이스를 확인해볼까요?
fmt.Println(copySlice) // 결과: [2 3 4]
}
이 예제에서는 original[1:4]
라는 표현을 사용해서 original
슬라이스의 1번 인덱스(값 2)부터 3번 인덱스(값 4)까지의 요소들을 copySlice
로 복사했습니다.
이렇게 하면 필요한 부분만 효율적으로 복사할 수 있겠죠?.
두 번째 방법: 만능 재주꾼 append
함수로 복사하기!
슬라이스를 복사하는 또 다른 방법으로는 append
함수를 활용하는 것이 있습니다.append
함수는 원래 슬라이스에 새로운 요소들을 추가하는 데 사용되지만, 조금만 응용하면 슬라이스 전체를 복사하는 데에도 쓸 수 있답니다.
package main
import "fmt"
func main() {
// 원본 슬라이스
original := []int{1, 2, 3, 4, 5}
// append 함수를 사용해서 슬라이스를 복사합니다.
// 텅 빈 슬라이스에 원본 슬라이스의 모든 요소를 추가하는 방식이에요.
copySlice := append([]int{}, original...)
// 복사된 슬라이스를 확인해봅시다.
fmt.Println(copySlice) // 결과: [1 2 3 4 5]
}
이 코드가 어떻게 작동하는지 살펴볼까요?.
[]int{}
는 아무 요소도 없는, 텅 빈 정수형 슬라이스를 의미합니다.append
함수에 이 텅 빈 슬라이스와 함께original...
을 전달했는데요.
여기서original...
은original
슬라이스 안에 있는 모든 요소들을 하나씩 꺼내서 펼쳐놓는다는 특별한 의미를 가집니다.
(마치 "original 슬라이스에 있는 거 전부 다!" 라고 외치는 것과 같아요.)
결국, 텅 빈 슬라이스에 original
슬라이스의 모든 요소들이 순서대로 추가되면서, copySlice
는 original
의 완벽한 복사본이 되는 것입니다.
이 방법도 꽤 간결하고 직관적이죠?.
슬라이스 복사, 이것만은 꼭 기억하세요! (중요 주의사항)
슬라이스를 복사하는 방법을 배웠으니 이제 마음껏 사용하면 될까요? 잠깐! 몇 가지 중요한 주의사항을 꼭 기억해야 합니다.
얕은 복사(Shallow Copy) vs 깊은 복사(Deep Copy): 뭐가 다를까요?
위에서 소개한 copy
함수나 append
함수를 이용한 방법은 기본적으로 '얕은 복사(Shallow Copy)'를 수행합니다.
이게 무슨 말이냐고요?
만약 슬라이스 안에 들어있는 요소들이 단순한 숫자나 글자가 아니라, 또 다른 슬라이스나 포인터(메모리 주소를 가리키는 특별한 변수)처럼 '주소 값'을 가지고 있는 경우를 생각해봅시다.
얕은 복사는 슬라이스라는 껍데기와 그 안에 담긴 주소 값들만 복사합니다.
그래서 복사된 슬라이스 안의 요소들이 가리키는 실제 데이터는 여전히 원본과 같은 곳을 바라보게 되는 건데요.
마치 한 집에 사는 두 가족이 같은 TV를 보는 것과 비슷하다고 할 수 있습니다.
한쪽에서 채널을 돌리면 다른 쪽도 영향을 받는 것처럼, 복사본에서 내부 요소의 값을 변경하면 원본의 내부 요소 값도 함께 바뀔 수 있다는 의미입니다.
만약 슬라이스 안에 담긴 참조 타입의 요소들까지 완전히 새롭게 복사해서, 원본과 복사본이 서로 전혀 영향을 주지 않도록 만들고 싶다면 '깊은 복사(Deep Copy)'를 해야 합니다.
깊은 복사는 조금 더 복잡해서, 슬라이스 안의 각 요소들을 하나하나 직접 새로 만들어서 복사해주는 과정이 필요한데요.
이는 상황에 따라 직접 코드를 작성해야 할 수도 있습니다.
새로운 슬라이스의 용량(Capacity)도 신경 써주세요!
make
함수로 새로운 슬라이스를 만들 때, 길이(length)뿐만 아니라 용량(capacity)도 지정할 수 있다는 사실, 알고 계셨나요?.
용량은 슬라이스가 실제로 메모리에 확보해둔 공간의 크기를 의미하는데요.
만약 copy
함수로 슬라이스를 복사할 때, 복사 받을 슬라이스의 용량을 길이보다 더 크게 만들어두면, 나중에 새로운 요소들을 추가할 때 메모리를 다시 할당하는 번거로운 과정을 줄일 수 있어서 성능에 약간의 이점을 줄 수도 있습니다.
물론, 단순 복사가 목적이라면 길이와 용량을 같게 만들어도 충분합니다.
마무리하며: 슬라이스 복사, 이제 자신감을 가지세요!
지금까지 고(Go) 언어에서 슬라이스를 효과적으로 복사하는 두 가지 주요 방법(copy
함수와 append
함수 활용)과 함께 몇 가지 중요한 주의사항들을 살펴봤습니다.
슬라이스가 참조 타입이라는 점, 그리고 얕은 복사와 깊은 복사의 차이점을 잘 이해하는 것이 안전하고 정확한 프로그래밍의 첫걸음인데요.
오늘 배운 내용들을 바탕으로 직접 코드를 작성하고 실행해보면서 슬라이스 복사에 대한 감을 익혀보시는 건 어떨까요?.
분명 고(Go) 언어를 다루는 여러분의 실력이 한층 더 성장하는 것을 느끼실 수 있을 겁니다!
'Go' 카테고리의 다른 글
고(Go) 개발자를 위한 필수템! 데이터베이스 마이그레이션, '구스(Goose)'로 쉽고 빠르게! (핵심 기능 총정리) (0) | 2025.05.30 |
---|---|
고(Go) 언어 전역 변수, 양날의 검! 똑똑하게 활용하는 방법은? (핵심 정리) (0) | 2025.05.30 |
고(Go) 언어 시간 다루기 완전 정복: time.Parse 함수, 이제는 마스터해볼까요? (0) | 2025.05.30 |
Go 언어 파일 쓰기 마스터 가이드: os, bufio 패키지로 원하는 내용 마음껏 저장하기! (고등학생 눈높이 완벽 해설) (0) | 2025.05.28 |
Go(고) 문자열 편집 마스터! strings.Replace로 원하는 글자만 쏙쏙 바꾸는 비법 (고등학생도 이해 쏙쏙!) (0) | 2025.05.28 |