var a []int // int형 슬라이스 선언
var a []int = make([]int, 5) // make 함수로 int형에 길이가 5인 슬라이스에 공간 할당
var b = make([]int, 5) // 슬라이스를 선언할 때 자료형과 [] 생략
c := make([]int, 5) // 슬라이스를 선언할 때 var 키워드, 자료형과 [] 생략
슬라이스에 공간을 할당할 것이므로 make 함수의 첫 번째 매개변수에는 대괄호에 길이를 설정하지 않은 상태로 자료형을 지정한다 그리고 두 번째 매개변수에는 슬라이스의 길이를 설정한다 이렇게 슬라이스를 생성하고 공간을 할당하면 슬라이스의 요소는 모두 0으로 초기화된다
슬라이스를 생성하면서 값을 초기화하려면 { } (중괄호)를 사용한다. 중괄호에서 값은 한 줄로 나열해도 되고 여러 줄로 나열해도 (여러 줄로 나열할 때는 마지막 요소에도 콤마를 붙여준다). 슬라이스이므로 대괄호에는 길이를 설정하지 않는다
a := []int{32, 29, 78, 16, 81} // 슬라이스를 생성하면서 값을 초기화
b := []int{
32,
29,
78,
16,
81, // 여러 줄로 나열할 때는 마지막 요소에 콤마를 붙임
}
var s = make([]int, 5, 10) // 길이가 5이고 용량이 10인 슬라이스 생성
a := make([]int, 5, 10)
fmt.Println(len(a)) // 길이는 5
fmt.Println(cap(a)) // 용량은 10
5
10
a := make([]int, 5, 10) // 길이가 5이면 a[0], a[1], a[2], a[3], a[4]가 생성
fmt.Println(a[4]) // 0: make 함수를 사용하면 슬라이스의 요소는 모두 0으로 초기화
fmt.Println(a[5]) // 길이를 벗어난 인덱스에 접근했으므로 런타임 에러 발생
fmt.Println(a[8]) // 길이를 벗어난 인덱스에 접근했으므로 런타임 에러 발생
0
panic: runtime error: index out of range
a := []int{1, 2, 3}
a = append(a, 4, 5, 6)
fmt.Println(a) // [1 2 3 4 5 6]
슬라이스에 다른 슬라이스를 붙이려면 append 함수를 사용할 때 ...을 사용한다
v
a := []int{1, 2, 3}
b := []int{4, 5, 6}
a = append(a, b...) // 슬라이스 a에 슬라이스 b를 붙일 때는 b...을 씀
fmt.Println(a) // [1 2 3 4 5 6]
[1 2 3 4 5 6]
a := [3]int{1, 2, 3}
var b [3]int
b = a // 배열의 요소가 모두 복사됨
b[0] = 9 // b[0]에 9를 대입하면 b의 첫 번째 요소만 바뀜
fmt.Println(a) // [1 2 3]
fmt.Println(b) // [9 2 3]
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]
슬라이스 a를 슬라이스 b에 대입하였다. 그리고 b[0]에 값을 대입한 뒤 값을 출력해보면 a[0]과 b[0] 모두 값이 바뀐다. 슬라이스는 레퍼런스 타입이라 값이 복사되지 않고 참조만하기 때문이다.
함수의 매개변수에 배열을 넘기면 복사가 되지만 슬라이스를 넘기면 참조만 하게된다. 따라서 함수 안에서 슬라이스의 요소를 변경하면 함수 바깥에 있는 슬라이스도 값이 바뀐다
copy(복사될 슬라이스, 원본 슬라이스)
a := []int{1, 2, 3, 4, 5}
b := make([]int, 3) // make 함수로 공간을 할당
copy(b, a) // 슬라이스 a의 요소를 슬라이스 b에 복사
fmt.Println(a) // [1 2 3 4 5]
fmt.Println(b) // [1 2 3]: 슬라이스 b의 길이는 3이므로 a의 요소 3개만 복사됨
슬라이스를 복사하였으므로 복사된 슬라이스의 요소를 바꾸어도 원본 슬라이스는 바뀌지 않는다.
a := []int{1, 2, 3}
b := make([]int, 3)
copy(b, a) // 슬라이스를 복사하였으므로
b[0] = 9 // b[0]만 바뀌고, a[0]은 바뀌지 않음
fmt.Println(a) // [1 2 3]
fmt.Println(b) // [9 2 3]
왜 슬라이스는 길이와 용량이 따로 구분되어 있을까? 앞서 슬라이스는 길이를 동적으로 늘릴 수 있다고 했다.
먼저 길이가 5이며 용량이 5인 슬라이스를 생성한다. 그리고 append 함수를 사용하여 값 두개를 추가한다
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(a) // [1 2 3 4 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[1:3]) // [2 3]
fmt.Println(a[2:5]) // [3 4 5]
a := []int{1, 2, 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]
fmt.Println(a[0:len(a)]) // [1 2 3 4 5]
fmt.Println(a[3:]) // [4 5]
fmt.Println(a[:3]) // [1 2 3]
fmt.Println(a[1:3]) // [2 3]
a := [5]int{1, 2, 3, 4, 5} // 배열 선언
b := a[:2] // 배열 a의 일부를 부분 슬라이스로 참조
b[0] = 9 // !!!!부분 슬라이스는 참조이므로 a[0], b[0]의 값이 모두 바뀜
fmt.Println(a) // [9 2 3 4 5]
fmt.Println(b) // [9 2]
!! 부분 슬라이스는 참조이므로 모두 값이 바뀜
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: 길이가 6이며 용량이 8인 슬라이스
fmt.Println(b) // [1 2 3 4 5 6]