개발자의 오르막
Golang 2차원 배열 문제를 통한 array, slice 의 개념정리 본문
이번 문제의 키워드는 Array, Slice, Make 이다. 해당 문제에서 하나의 배열을 2차원으로 만드는 방법으로는 슬라이스의 특징인 배열의 부분을 추출하는 기능을 활용하는 문제였습니다.
정답을 반환하는 answer 2차원 배열을 만들고, param으로 주어지는 num_list 1차원 배열을 특정 길이만큼 잘라서 할당하는 풀이입니다.
그러면 위의 세 키워드 Array, Slice, Make 에 대해 개념을 정리해보겠습니다.
Array
- Golang 에서 배열은 동일한 데이터 타입의 고정 크기 요소들의 순서화된 집합이다.
- 배열은 대괄호 [] 안에 크기를 지정하여 선언된다.
- var myArray [5] int
- myArray := [5]int{1,2,3,4,5}
- myArray := […]int{6,7,8,9,10}
- 배열의 요소 개수 만큼 크기가 지정된다.
- 배열에서 값을 할당할 때 index 와 value 값을 대입하는 방법으로 할당한다.
- myArray[0] = 1
- 배열의 크기는 선언 시에 결정되며, 변경할 수 없다. 즉, 배열의 크기가 고정되어 있으므로 요소를 추가하거나 제거할 수 없다.
- 따라서 배열은 선언하자마자 모든 인덱스는 초기값을 가지게 된다.
- var myArray [5]int → [0 0 0 0 0 ]
Slice
- Golang 에서의 슬라이스는 배열을 기반으로 한 동적 크기의 배열이다.
- 슬라이스는 대괄호안에 인덱스가 없는 형태로 선언된다.
- var mySlice []int
- 슬라이스는 가변크기의 배열이기 때문에 최초 선언 시 빈 값을 가지게 된다.
- var mySlice []int → []
- 따라서, 슬라이스의 초기값을 지정하기 않고 선언만 하면 Nil slice 가 된다.
- 슬라이스는 값을 대입할 때 요소에 값을 할당하는 방법과 append 함수를 사용하여 새로운 요소를 추가하는 방법이 있다.
- mySlice[0] = 5
- mySlice = append(mySlice, 5)
- 슬라이스는 배열의 일부분을 슬라이스로 생성할 수 있다.
myArray := [5]int{1,2,3,4,5}
mySlice := myArray[1:4]
Slice 추가, 병합, 복사
append (추가, 병합)
- append() 는 Golang 의 내장된 함수 (builtin.go) 이다.
- 슬라이스는 append() 함수를 이용해서 데이터를 추가할 수 있다.
- 용량 내에서는 길이를 변경하여 데이터를 추가하며, 용량이 초과하는 경우에는 설정한 용량만큼 새로운 배열을 생성하고, 기존 배열 값들을 모두 새 배열에 복제한 후 다시 슬라이스를 할당하는 방식이다.
# 슬라이스에 요소를 추가하는 방법
a := []int{1,2,3}
a = append(a, 4)
fmt.Println(a) -> [1 2 3 4]
# 두 슬라이스를 병합하는 방법
a := []int{1,2,3}
b := []int{4,5,6}
a = append(a, b)
fmt.Println(a) -> [1 2 3 4 5 6]
copy (복사)
- copy() 는 Golang 의 내장된 함수 (builtin.go) 이다.
- 슬라이스는 copy() 함수를 이용해서 데이터를 복사할 수 있다.
- copy(붙여넣을 슬라이스, 복사할 슬라이스)
a := []int{1,2,3}
b := make([]int, len(a), cap(a)*2)
copy(a, b)
fmt.Println(a) -> [1 2 3 4 5 6]
- b의 용량이 a보다 큼으로, copy 를 할 때 a의 요소를 모두 가지게된다.
a := []int{1,2,3}
b := []int{4,5}
copy(b, a)
fmt.Println(a) -> [1 2]
- b의 용량이 a보다 작거나 같을 때, b는 a의 요소들을 덮어씌우게 된다.
a := []int{1,2,3}
b := a[1:2]
fmt.Println(b) -> [2]
a := []int{1,2,3}
b := a[:2]
fmt.Println(b) -> [1,2]
- 슬라이스 := 복사할 슬라이스(복사할 첫 인덱스 : 복사할 마지막 인덱스+1)
- 앞의 첫 인덱스가 없을 경우 0부터 복사한다.
Make
- Make 함수는 Golang 의 내장된 함수(builtin.go)로, slice, map, channel 등의 빈(empty) 데이터 구조를 생성하고 초기화할 때 사용됩니다.
- make(T, args)
- T는 Make 함수로 생성하고자 하는 데이터 타입을 나타냅니다.
- args 는 데이터 구조를 초기화하기 위한 인자(argument)를 나타냅니다.
- s := make([]int, 5, 10)
- 위의 코드는 []int 타입의 길이가 5이며, 용량이 10인 슬라이스를 선언한 것을 의미합니다.
- 길이가 5로 정해져있으므로, 초기 선언된 슬라이스는 [0 0 0 0 0] 값을 지니고 있습니다.
- s := make(map[string]int, 10)
- 위의 코드는 map[string]int 타입의 용량이 10인 슬라이스를 선언한 것을 의미합니다.
Array vs Slice
먼저 Array 와 Slice 에 대해 아래 표와 같이 차이점이 정리되어 있습니다.
타입
- 위의 표에 보면 배열의 타입은 값(value) 이며, 슬라이스는 참조(reference) 로 되어있다.
- 배열은 하나의 값으로 불면의 성격을 가지며, 상수라고도 생각될 수 있다.
a := [3]int{1,2,3}
b := a
b[0] = 4
fmt.Println(a) -> [1 2 3]
fmt.Println(b) -> [4 2 3]
- 반면에, 슬라이스는 배열의 일부분으로서, 참조하기 때문에 포인터를 사용한다.
- 슬라이스는 다른 변수에 할당하면 원래의 배열을 참조하게 된다.
a := []int{1,2,3}
b := a
b[0] = 4
fmt.Println(a) -> [4 2 3]
fmt.Println(b) -> [4 2 3]
용량과 길이
- 용량(capacity) 은 데이터 구조가 저장할 수 있는 최대 수를 나타내며, 길이(lencgh) 는 데이터 구조에 저장된 요소의 수를 의미한다.
- 따라서 배열의 경우 선언 시 요소의 크기가 정해지고, 값이 불변하기 때문에 용량과 길이가 정해진다.
- 그러나 슬라이스의 경우 요소의 수가 동적으로 크기가 조정가능한 배열이기 때문에 용량과 길이가 변할 수 있다.
비교연산
- 배열의 타입은 값이며, 슬라이스의 타입은 참조입니다.
- 따라서, 동일한 두 배열을 비교할 때는 값 끼리의 비교이므로 true 가 될 수 있습니다.
a := [3]int{1,2,3}
b := [3]int{1,2,3}
fmt.Println(a == b) -> true
- 그러나 슬라이스는 배열의 참조이기 때문에, 두 슬라이스를 비교하는 것은 불가능하며, 두 슬라이스의 요소들의 일치여부는 비교할 수 있습니다.
메모리할당
- 배열은 선언 시부터 배열의 고정된 크기가 정해지기 때문에 컴파일 시점에서 메모리가 할당됩니다.
- 슬라이스는 동적으로 크기가 결정되기 때문에 메모리 공간이 달라질 수 있어 런타임 시점에서 메모리가 할당됩니다. 원래 슬라이스의 용량보다 많은 요소가 할당될 경우에는 더 큰 공간을 할당하고 기존 슬라이스의 요소를 복사하는 작업이 진행됩니다.
Reference
'GoLang' 카테고리의 다른 글
Golang Logrus 로 Json Logging 하기 (0) | 2022.11.03 |
---|---|
Go, Makefile, Docker로 프로젝트 셋팅 및 빌드 정보 활용하기 (0) | 2022.10.08 |
Golang 과 TDD (0) | 2022.10.02 |
golang과 Docker로 환경변수 제어하기 (0) | 2022.08.23 |
GoLang 의 포인터 (0) | 2022.07.03 |
Comments