[Go] 깊은 복사, 얕은 복사

Deagwon Bu·2022년 7월 7일
0

Go

목록 보기
5/9
post-thumbnail

값의 저장과 참조

사람이 프로그램한 변수(sysbolic address)는 특정 메모리 주소를 가리키고, 이 메로리 주소에는 실제 프로그램이 실행중에 사용되는 “값”이 저장되어 있다.

깊은 복사

값의 깊은 복사라고 하면, 이 실제 메모리에 값을 복사하여 물리적으로 다른 공간에 동일한 값을 저장한다.

얕은 복사

이와 반대로 얕은 복사는 변수명이 동일한 메모리 주소를 가리키도록 하는 것이다. 물리적으로 메모리의 123번지에만 “hello”라는 값이 저장되어 있지만, variable_a로 접근해도 “hello”라는 값을 얻을 수 있고, variable_b로 접근해도 “hello”라는 값을 얻을 수 있다.

Variable

Go의 일반 변수들은 깊은 복사가 일어난다.

variable_a := "hello"
variable_b := "hi"

variable_b = variable_a

참조형 변수 - Slice

참조형 변수(배열, 포인터, 클래스 객체)를 단순 할당문 형태로 복사하면 얕은 복사가 일어난다.

얕은 복사

	// 0. 원본 생성
	slice := []int{0, 10, 20, 30}

	// 1. 단순 대입
	copyslice := slice

깊은 복사

1. copy함수

	// 0. 원본 생성
	slice := []int{0, 10, 20, 30}

	// 1. 원본과 동일한 크기의 슬라이스 생성
	copyslice := make([]int, len(slice))

	// 2. copy 함수로 슬라이스 복사
	copy(copyslice, slice)

2. Slice 전체 인덱싱

	// 0. 원본 생성
	slice := []int{0, 10, 20, 30}

	// 1. 전체 인덱싱
	copyslice := slice[:]

3. 순회 하면서 대입

// 0. 원본 생성
slice := []int{0, 10, 20, 30}

// 1. 원본과 동일한 크기의 슬라이스 생성
copyslice := make([]int, len(slice))

// 2. 순회 하면서 대입
for idx, item := range slice{
	copyslice[idx] = item
}

4. 순회 하면서 append

// 0. 원본 생성
slice := []int{0, 10, 20, 30}

// 1. 빈 슬라이스 생성
var	copyslice []int

// 2. 순회 하면서 append
for idx, item := range slice{
	copyslice = append(copyslice, item)
}

참조형 변수 - Class

깊은 복사

참조형 변수를 복사하기 위해서는 값을 직접 할당하거나 encoding-decoding하는 방법을 거쳐야 한다.

직접 할당

가장 단순한 방법으로 직접 값을 할당하는 방법이 있다. 이러한 방법은 단순하지만, ClassEx가 변경될 경우, 복사하는 코드도 변경해야하는 단점이 있다.

type ClassEx struct {
	name string
	value int
}

classA := ClassEx{"hi", 123}

classB := ClassEx{classA.name, classA.value}

Encoding-Decoding

ClassEx가 변경되어도, 코드를 그대로 사용하기 위해서는 다른 방법이 필요하다. 대표적으로 객체를 특정 포맷으로 인코딩한 후, 다시 원래 포맷으로 디코딩하는 방법이 있다. (이렇게 어떤 객체를 임의의 포맷으로 변환하는 것을 직렬화(serialization)이라고 한다.)

type ClassEx struct {
	name string
	value int
}

// 원본 객체 생성
classA := &ClassEx{"hi", 123}

// buffer, encoder, decoder생성
var buffer bytes.Buffer
encoder := gob.NewEncoder(&buffer)
decoder := gob.NewDecoder(&buffer)

// 원본객체 인코딩
encoder.Encode(classA)

// buffer의 값을 디코딩하여 classB로 깊은 복사
var classB *ClassEx
decoder.Decode(&classB)

이때 gob의 인코더는 객체를 직접 입력받지 않고 객체의 주소를 입력 받기 때문에 중간에 포인터 변수를 두었다.

Reference

0개의 댓글