여름의 서재
[Go 기초] 슬라이스 (Slice) 본문
슬라이스
Go 배열은 고정된 배열크기 안에 동일한 타입의 데이타를 연속적으로 저장하지만, 배열의 크기를 동적으로 증가시키거나 부분 배열을 발췌하는 등의 기능을 가지고 있지 않다. 하지만 슬라이스는 배열과 달리 고정된 크기를 미리 지정하지 않을 수 있고, 차후 그 크기를 동적으로 변경할 수도 있고, 또한 부분 배열을 발췌할 수도 있다.
Go Slice 선언은 배열을 선언하듯이 "var v []T" 처럼 하는데 배열과 달리 크기는 지정하지 않는다. 예를 들어, 정수형 Slice 변수 a를 선언하기 위해서 "var a []int" 처럼 선언할 수 있다.
package main
import "fmt"
func main() {
var a []int //슬라이스 변수 선언
a = []int{1, 2, 3} //슬라이스에 리터럴값 지정
a[1] = 10
fmt.Println(a) // [1, 10, 3]출력
}
📌 fmt.Println()은 stdout 으로 표준 문자열 출력을 제공하는 함수입니다.
println()은 내장된 함수로 stderr를 출력해주는 내장함수 입니다. -> 때문에 pringln()은 주로 디버깅할 때 유용 하다고!
Go에서 Slice를 생성하는 또 다른 방법으로 Go의 내장함수 make() 함수를 이용할 수 있다. make() 함수로 슬라이스를 생성하면, 개발자가 슬라이스의 길이(Length)와 용량(Capacity)을 임의로 지정할 수 있는 장점이 있다. make() 함수의 첫번째 파라미터에 생성할 슬라이스 타입을 지정하고, 두번째는 Length (슬라이스의 길이), 그리고 세번째는 Capacity (내부 배열의 최대 길이)를 지정하면, 모든 요소가 Zero value인 슬라이스를 만들게 된다. 여기서 만약 세번째 Capacity 파라미터를 생략하면 Capacity는 Length와 같은 값을 갖는다. 그리고 슬라이스의 길이 및 용량은 내장함수 len(), cap()을 써서 확인할 수 있다.
func main() {
s := make([]int, 5, 10)
println(len(s), cap(s)) // len 5, cap 10
}
슬라이스에 별도의 길이와 용량을 지정하지 않으면, 기본적으로 길이와 용량이 0 인 슬라이스를 만드는데, 이를 Nil Slice 라 하고, nil 과 비교하면 참을 리턴한다.
func main() {
var s []int
if s == nil {
println("Nil Slice")
}
println(len(s), cap(s)) // 모두 0
}
슬라이스에서 일부를 발췌하여 부분 슬라이스를 만들 수 있다.
package main
import "fmt"
func main() {
s := []int{0, 1, 2, 3, 4, 5}
s = s[2:5]
fmt.Println(s) //2,3,4 출력
}
배열은 고정된 크기로 그 크기 이상의 데이타를 임의로 추가할 수 없지만, 슬라이스는 자유롭게 새로운 요소를 추가할 수 있다. 슬라이스에 새로운 요소를 추가하기 위해서는 Go 내장함수인 append()를 사용한다. append()의 첫 파라미터는 슬라이스 객체이고, 두번째는 추가할 요소의 값이다. 또한 여러 개의 요소 값들을 한꺼번에 추가하기 위해서는 append() 두번째 파라미터 뒤에 계속하여 값을 추가할 수 있다.
func main() {
s := []int{0, 1}
// 하나 확장
s = append(s, 2) // 0, 1, 2
// 복수 요소들 확장
s = append(s, 3, 4, 5) // 0,1,2,3,4,5
fmt.Println(s)
}
📌 내장함수 append()가 슬라이스에 데이타를 추가할 때, 내부적으로 다음과 같은 일이 일어난다. 슬라이스 용량(capacity)이 아직 남아 있는 경우는 그 용량 내에서 슬라이스의 길이(length)를 변경하여 데이타를 추가하고, 용량(capacity)을 초과하는 경우 현재 용량의 2배에 해당하는 새로운 Underlying array (주: 아래 내부구조 참조) 을 생성하고 기존 배열 값들을 모두 새 배열에 복제한 후 다시 슬라이스를 할당한다. ... (신기하네..? 👍)
한 슬라이스를 다른 슬라이스 뒤에 병합하기 위해서는 아래 예제와 같이 append()를 사용한다. 이 append 함수에서는 2개의 슬라이스를 파라미터로 갖는데, 처음 슬라이스 뒤에 두번째 파라미터의 슬라이스를 추가하게 된다. 여기서 한가지 주의할 것은 두번째 슬라이스 뒤에 ... 을 붙인다는 것인데, 이 ellipsis(...)는 해당 슬라이스의 컬렉션을 표현하는 것으로 두번째 슬라이스의 모든 요소들의 집합을 나타낸다. 즉, 아래 예제에서 sliceB... 는 4, 5, 6 으로 치환된다고 볼 수 있다.
package main
import "fmt"
func main() {
sliceA := []int{1, 2, 3}
sliceB := []int{4, 5, 6}
sliceA = append(sliceA, sliceB...)
//sliceA = append(sliceA, 4, 5, 6)
fmt.Println(sliceA) // [1 2 3 4 5 6] 출력
}
이러한 추가/확장 기능과 더불어, Go 슬라이스는 내장함수 copy()를 사용하여 한 슬라이스를 다른 슬라이스로 복사할 수도 있다. 아래 예제는 3개의 요소를 갖는 소스 슬라이스를 그 2배의 크기 즉 6개를 갖는 타겟슬라이스로 복사하는 예를 보여준다. (주: 아래에서 설명하듯이 슬라이스는 실제 배열을 가리키는 포인터 정보만을 가지므로, 복사를 좀 더 정확히 표현하면, 소스 슬라이스가 갖는 배열의 데이타를 타겟 슬라이스가 갖는 배열로 복제하는 것임)
func main() {
source := []int{0, 1, 2}
target := make([]int, len(source), cap(source)*2)
copy(target, source)
fmt.Println(target) // [0 1 2 ] 출력
println(len(target), cap(target)) // 3, 6 출력
}
출처: http://golang.site/go/article/13-Go-%EC%BB%AC%EB%A0%89%EC%85%98---Slice
'Skill > Golang' 카테고리의 다른 글
[Go 기초] 맵 (Map) (1) | 2022.04.13 |
---|---|
[Go 기초] 배열 (Array) (0) | 2022.04.13 |
[Go 기초] 클로저 (0) | 2022.04.13 |
[Go 기초] 함수 (0) | 2022.04.13 |
[Go 기초] 조건문 & 반복문 (0) | 2022.04.13 |