Notice
Recent Posts
Recent Comments
Link
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
Archives
Today
Total
관리 메뉴

Code Habit

Go ) 슬라이스 - 레퍼런스 타입, 복사, 부분 슬라이스 본문

카테고리 없음

Go ) 슬라이스 - 레퍼런스 타입, 복사, 부분 슬라이스

코드베어 2020. 5. 18. 10:33

슬라이스는 레퍼런스 타입이다. 내장된 배열에 대한 포인터이므로 슬라이스끼리 대입하면 값이 복사되지 않고 참조(레퍼런스)만 한다.

a := []int{1, 2, 3}
var b []int		// 슬라이스로 선언

b = a			// a를 b에 대입해도 요소가 모두 복사되지 않고 참조만 함
b[0] = 9		// 슬라이스는 참조이므로 a[0], b[0]의 값이 모두 바뀜

fmt.Println(a) // [9 2 3]
fmt.Println(b) // [9 2 3]

마찬가지로 함수의 매개변수에 배열을 넘기면 복사가 되지만 슬라이스를 넘기면 참조만 하게 된다. 따라서 함수 안에서 슬라이스의 요소를 변경하면 함수 바깥에 있는 슬라이스도 값이 바뀐다.

 

슬라이스의 요소를 모두 복사할 때는 copy 함수를 사용한다.

  • copy(복사될 슬라이스, 원본 슬라이스)
a := []int{1, 2, 3, 4, 5}
b := make([]int, 3)

copy(b, a)

fmt.Println(a)  // [1 2 3 4 5]
fmt.Println(b)  // [1 2 3] : 슬라이스 b의 길이는 3이므로 a의 요소 3개만 복사됨

복사될 슬라이스 b에는 make 함수로 공간을 할당해야 한다. 공간을 할당하지 않은 빈 슬라이스에는 요소를 복사할 수 없다. 슬라이스를 복사하였으므로 복사된 슬라이스의 요소를 바꾸어도 원본 슬라이스는 바뀌지 않는다.

 

Go언어는 동적 배열을 구현하기 위해 길이와 용량을 구분하고 있다. 슬라이스의 요소가 늘어나면 Go 런타임은 정해진 알고리즘에 의해 슬라이스의 용량을 늘린다.

a := []int{1, 2, 3, 4, 5}
fmt.Println(len(a), cap(a)) // 5 5 : 길이가 5이며 용량이 5인 슬라이스

a = append(a, 6, 7)         // 슬라이스 a에 값 6, 7을 추가

fmt.Println(len(a), cap(a)) // 7, 10: 길이가 7이며 용량이 10인 슬라이스, 용량이 늘어남 !

 

슬라이스는 기존 슬라이스에서 일정 위치를 지정하여 부분 슬라이스를 만들 수 있다.

  • 슬라이스[시작인덱스:끝인덱스]
a := []int{1, 2, 3, 4, 5}

b := a[0:5] // a의 인덱스 0부터 5까지 참조

fmt.Println(b) // [1 2 3 4 5]

부분 슬라이스는 슬라이스의 시작 인덱스부터 끝 인덱스까지 일부만 참조한다. 여기서 끝 인덱스는 실제 인덱스보다 1이 더 많다. 따라서 길이가 5인 슬라이스를 처음부터 끝까지 모두 참조하려면 [0:4]가 아닌 [0:5]가 된다. 또한 복사가 아니라 참조이므로 부분 슬라이스의 내용을 바꾸면 기존 슬라이스의 내용도 바뀐다. 슬라이스의 인덱스는 생략할 수 있다. 단 생략할 때 각 인덱스의 끝을 가리킨다.

a := []int{1, 2, 3, 4, 5}

fmt.Println(a[0:3]) // [1 2 3]
fmt.Println(a[2:5]) // [3 4 5]

fmt.Println(a[:]) // [1 2 3 4 5]
fmt.Println(a[0:])// [1 2 3 4 5]
fmt.Println(a[:5])// [1 2 3 4 5]

b := a[:]
b[0] = 6

fmt.Println(a) // [6, 2, 3 ,4 ,5]

 

부분 슬라이스는 슬라이스뿐만 아니라 배열에도 사용할 수 있다. 물론 참조이기 때문에 배열이라도 부분 슬라이스의 요소를 바꾸면 배열의 요소도 바뀐다.

a := [5]int{1, 2, 3, 4, 5} // 배열 선언

b := a[:2]
b[0] = 9

fmt.Println(a) // [9 2 3 4 5]

 

부분 슬라이스를 만들면서 용량도 지정할 수 있다.

  • 슬라이스[시작_인덱스:끝_인덱스:용량]
a := []int{1, 2, 3, 4, 5, 6, 7, 8}

b := a[0:6:8]	// 인덱스 0부터 6까지 가져와서 부분 슬라이스로 만들고 용량을 8로 설정

fmt.Println(len(b), cap(b)) // 6 8

단 용량을 설정할 때 기존 슬라이스의 용량을 넘을 수는 없다.