golang 슬라이스 Slices
1) 슬라이스 slices
-
배열과 비슷하지만, 길이가 고정되어 있는 배열과 달리 동적으로 크기를 변경하여 사용할 수 있다
- 배열을 내장하고 있음
-
[]type : 배열과 달리 [] 안에 숫자나 … 넣지 않음!!
// 방법 1 : 빈 슬라이스 (슬라이스 길이 0) var a []int // 방법 2 : 생성과 동시에 초기화 가능 b := []int{1,2,3,4} // 방법 3 c := make([]int, 5)
- 빈 슬라이스는 nil 값을 가짐 []
- nil 은 null 과 비슷한 개념!
- nil 슬라이스는 길이의 최대 크기가 0
- 빈 슬라이스는 nil 값을 가짐 []
make() : 값을 넣을 공간 할당
-
슬라이스에 값을 넣기 위해서는 make() 를 사용하여 공간을 할당해 주어야 함
- 만약 그냥 빈 슬라이스를 선언하면 공간이 없어서 값을 못 넣어 ( 빈 슬라이스 a에 a[0] = 2 하면 에러)
- 대신 다른 슬라이스를 대입해서 슬라이스 참조는 가능
-
슬라이스의 요소는 모두 0으로 초기화 된다
// 방법 1 var a []int = make([]int, 3) // 방법 2 var b = make([]int, 3) // 방법 3 a := make([]int, 3)
- 모두 [0 0 0]
make( []자료형, 길이, 용량 )
-
길이
-
인덱스로 접근 가능한 최대 공간**
- 용량이 더 확보되어 있더라도 길이 이상으로 접근하려고 하면 에러
- len()
-
- 용량
- 요소가 추가되면 자동으로 늘어나는 공간
- 실제 메모리에 할당된 공간
- cap()
-
용량 >= 길이
- make() 에서 용량을 생략하면 자동으로 용량==길이
-
용량을 처음부터 많이 할당하면 요소가 추가될 때마다 메모리를 일일이 할당하지 않아도 돼서 성능상 이점이 있음 (단, 처음부터 너무 메모리를 잡아먹어)
- 용량을 작게 할당하면 요소가 추가될 때마다 메모리를 할당해줘야 해서 성능이 떨어질 수 있음 (단, 메모리 공간을 적게 차지)
a := make([]int, 3, 7) // [0 0 0]
len(a) // 3
cap(a) // 7
- 잠재(?) 공간이 4개 더 있음! (용량 7인데 길이 3으로 공간 3개 사용했으니까 4개 더 남았다)
- a 에 4개의 요소 값을 더 추가하면 공간이 이미 할당되어 있으니까 메모리 할당을 안 해줘도 돼
- 이제 4개 초과로 값을 추가하면 더이상 할당된 공간이 없어서 용량을 늘려야 함 (메모리 추가 할당)
append() : 값 & 슬라이스 추가하기
-
값을 추가
a := []int{1,2,3} a = append(a,4,5,6) fmt.Println(a) // [1 2 3 4 5 6]
-
슬라이스에 다른 슬라이스를 붙이기
a := []int{1,2,3} b := []int{4,5,6} a = append(a,b...) fmt.Println(a) // [1 2 3 4 5 6]
2) 슬라이스는 레퍼런스 타입!
-
슬라이스는 내장된 배열에 대한 포인터
-
그래서 a 슬라이스에 b 슬라이스를 대입해도 값이 복사되는 것이 아니라 주소값이 복사 -> 참조
( 배열은 대입하면 값을 그대로 복사함)
-
배열의 경우
// 배열의 경우 a := [2]int{1,2} var b [2]int b = a // 배열 a의 값을 그대로 복사 [1 2] b[0] = 3 fmt.Println(a) // [1 2] fmt.Println(b) // [3 2]
- 배열 b는 배열 a의 값을 그대로 복사한 서로 다른 배열이기 때문에 b 요소의 값을 변경해도 a 에는 영향을 끼치지 않음
-
슬라이스의 경우
// 슬라이스의 경우 a := []int{1,2} var b []int b = a b[0] = 7 // 주소에 있는 값을 변경 fmt.Println(a) // [7 2] fmt.Println(b) // [7 2]
- 서로 다른 슬라이스가 아니라 같은 주소값을 참조하기 때문에 하나의 값을 변경하면 둘 다 변경됨
copy(b, a) : b 에다가 a 값 복사
-
슬라이스의 요소를 복사하고 싶을 때 사용한다
-
값만 복사한 서로 다른 슬라이스 !
a := []int{1,2,3} b := make([]int, 4) // [0 0 0 0] c := make([]int, 1) // [0] copy(b, a) copy(c, a) fmt.Println(a) // [1 2 3] fmt.Println(b) // [1 2 3 0] fmt.Println(c) // [1]
- 이때 var b []int 같이 빈슬라이스를 선언하면 값을 못 넣음
- c 의 길이는1 이라 a 의 값들 중 1개만 복사해올 수 있음
-
서로 다른 슬라이스가 되기 때문에 요소값을 변경해도 다른 슬라이스에 영향을 끼치지 않음!
a[0] = 100 fmt.Println(a) // [100 2 3] fmt.Println(b) // [1 2 3 0]
3) 부분 슬라이스 [beg : end]
-
sliceA[beg : end]
-
sliceA의 인덱스 beg 부터 end-1 까지 참조한 슬라이스를 만든다
-
슬라이스의 값을 직접 복사한게 아니라서 부분 슬라이스의 일부를 바꾸면 원본 슬라이스의 값도 바뀜 (슬라이스는 레퍼런스 타입!!)
( 배열이라도 부분 슬라이스를 할 경우 레퍼런스 타입처럼 취급 - 참조)
-
참조가 싫으면 copy() 써서 부분 값을 복사해오면 돼
- copy(b, a[0:3]) 값만 복사해와서 서로 영향 XX
-
-
예시
a := []int{1,2,3,4} b := a[1:3] // a 슬라이스의 인덱스 1 2 값 참조 fmt.Println(a) // [1 2 3 4] fmt.Println(b) // [2 3]
b[0] = 100 fmt.Println(a) // [1 100 3 4] fmt.Println(b) // [100 3]
- 레퍼런스 타입이기 때문에 하나의 값을 변경하면 다른 슬라이스에도 영향을 미침
-
sliceB := sliceA[beg : end : capacity]
- 부분 슬라이스 할 때 용량을 지정해 줄 수 있음
- 단 원본 슬라이스의 용량을 넘으면 안돼!
Comments