Golang - 슬라이스

Lumi·2022년 2월 10일
0

Golang

목록 보기
12/38
post-thumbnail

🔥 슬라이스 - 1

Go에서 가장 많이 사용하는 방법으로 동적배열을 말합니다.

  • 길이에 제한이 없는 배열

선언하는 방법은 어렵지 않습니다.

  • 배열을 선언하듯이 선언을 하면 됩니다.

하지만 그렇다고 완전한 동적배열을 의미하는것은 아니고 ArrayList라고 생각을 하면 됩니다.

func main() {
	var 변수명 []int
    
    if len(변수명) == 0 {
    	fmt.Println("slice의 길이는 0 입니다.")
    }
    
    변수명[1] = 10
    fmt.Println(변수명)
}

이 코드를 실행시키면 에러가 나게 됩니다.

왜냐하면 ArrayList의 형태를 띄고 있기 떄문에 0에 해당하는 값이 없이 바로 1에는 집어넣을수 없기 떄문입니다.

  • ArrayList는 이전값이 현재값을 가르키는 방식으로 작동을 합니다.

초기화를 하는 방법은 내장함수를 사용하는 방법과 하드코딩 하는 방법이 있습니다.

a := make([]int,3)
- [0,0,0]과 같습니다.

a := []int{0,0,0}
- 위 코드와 같은 결과를 내뱉습니다.

js의 push와 같은 역할을 하는 append

slice := []int{1,2,3}

slice2 := append(slice, 4)

fmt.Println(slice)
fmt.Println(slice2)

js의 push내장함수와 같은 역할을 하는 내장함수 입니다.

기존의 변수는 그대로 유지시키면서 완전히 새로운 변수를 생성해 냅니다.

만약 기존 변수를 변화시키고 싶으면

  • slice = append(slice,4) 이렇게 적어주면 됩니다.
  • 여러개를 추가할떄에는 append(slice,4,5,6,7)

새로운 변수를 만드는 행위는 메모리를 잡아먹기 떄문에 주의해야 합니다.

슬라이스의 동작원리

앞서 적은 내용은 굉장히 쉽고 다가가기에 어렵지 않습니다.

하지만 내부에서 작동하는 구조를 자세히 살펴보아야 후에 발생하는 문제를 해결할수 있습니다.

type SliceHeader struct {
	Data unitptr // 실제 배열을 가르키는 값
    Len int // 배열의 길이
	Cap int // capacity : 용량을 의미
}

예를들어보면

data는 값을 의미하기 떄문에 어렵지 않습니다.

Len값은 배열의 길으를 의미하기 떄문에 []int{1,2,3,4,5}와 같은 구문에서 5를 의미합니다.

Cap는 용량을 의미하며 Len과 비슷하지만 Len은 실제로 사용되는 부분을 의미하고 Cap는 최대 사용할수 있는 값으로 인식할수 있습니다.

그러기 떄문에 좀더 정확하게 말을 하자면

슬라이스는 Go에서 제공하는 배열을 가리키는 포인터 입니다.

좀더 Caplen의 차이점을 알아보면

slice := make([]int, 3, 5)라는 코드를 살펴 보면 차이점을 명확하게 알수 있습니다.

앞서 배운것처럼 make라는 내장함수는 초기화를 시켜주는 함수이며 이처럼 인자값을 3개까지 넣을수 있습니다.

이떄 3은 Len을 의미하고, 5는 Cap를 의미합니다.

  • [0][0][0][][]이 만들어 지게 될 것이고
  • 이러한 기준에서 보았을떄 Len값은 = 3, Cap값은 = 5라는 것을 알수 있습니다.

array와 slice의 차이

func changeArray(array2 [5]int){
	array2[2] = 200
}	

func changeSlice(slice2 []int){
	slice2[2] = 200
}

func main(){
	array := [...]int{1,2,3,4,5}
    slice := []int{1,2,3,4,5}
    
    changeArray(array)
    changeSlice(slice)
    
    fmt.Println(array)
    fmt.Println(slice)
}

이 결과를 보면 array는 바뀌지 않고 slice는 바뀌게 됩니다.

앞서 한번 다루었던 것처럼 array과 array2는 다룬 주소값을 가지게 되기 떄문에 변화가 없는 것 입니다.

반면에 slice같은 경우에는 구조상 가르키고 있는 데이터값이 있기 떄문에 함수로 들어가도 똑같은 주소값을 가르키게 됩니다.

append()의 동작원리

생각보다 심오하고 어려운 내용이였습니다.

간단하게 설명하면 깊은복사와 얕은복사에 대한 내용이 될 것 같습니다.

slice := make([]int, 3, 5)

- 이렇게 만들어 Len = 3 , Cap = 5인 slice가 만들어 집니다.

slice2 := append(slice, 4,5)

- 이후 append를 적용시키면 [0][0][0][4][5]라는 값이 만들어 집니다.

이떄 slice[1] = 100을 적용하면 어떻게 될까요

결과는 : slice, slice2모두 바뀌게 됩니다.

왜냐하면 같은 주소값을 가지게 되기 때문입니다.

  • 깊은 복사라고도 하죠

다른 주소값을 가지게 되는 경우는 Cap와 Len이 동일한 값을 가질 떄 입니다.

slice := make([]int, 5, 5)

를 만들어 주면 cap와 len이 같은 값을 가지고 있는 상태가 되기 떄문에 만약

slice2 := append(slice, 4,5)

를 적용하면 새로운 값을 만들어서 그곳에 값을 복사후 값을 삽입하는 작업이 진행이 됩니다.

그러기 떄문에 다른 주소값을 가진 slice가 만들어 지고

slice[1] = 200 의 결과로는 slice만 변하게 됩니다.
profile
[기술 블로그가 아닌 하루하루 기록용 블로그]

0개의 댓글