Golang 배열(array) 슬라이스(slice) 사용법 차이

Go에서는 배열보다는 슬라이스를 많이 사용합니다.

둘은 비슷하지만 차이점이 있습니다.

배열과 슬라이스는 어떤 점이 다른지 먼저 보겠습니다.

1. 배열은 크기는 고정, 슬라이스 크기는 가변

2. 배열은 복사하면 별도 메모리를 생성.

   슬라이스는 복사할 경우 같은 곳을 참조

 

먼저 간단하게 사용 방법을 알아보겠습니다.

 

선언 방법

배열(array)과 슬라이스(slice)를 선언할 때 차이가 있습니다.

즉, 선언을 어떻게 하는지에 따라 배열이 되는지 슬라이스가 되는지 정해집니다.

 

배열 선언 방법

package main

import "fmt"

func main() {
	arr1 := [5]int{1, 2, 3, 4, 5}
	arr2 := [...]int{6, 7, 8, 9, 10}

	fmt.Println(arr1)
	fmt.Println(arr2)
}

 

배열 선언을 할 때에는 배열 크기를 지정합니다.

변수 arr1 처럼 5라고 명시적으로 크기를 지정합니다.

변수 arr2 처럼 […] 을 사용하면 요소 개수만큼 크기가 지정됩니다.

이번에는 슬라이스를 정의하는 방법을 보겠습니다.

 

슬라이스 선언 방법

package main

import "fmt"

func main() {
	slice1 := []int{1, 2, 3, 4, 5}

	fmt.Println(slice1)
}

 

슬라이스 변수를 정의할 때는 크기를 지정하지 않았습니다.

배열은 크기가 고정되어 있지만 슬라이스는 가변 배열입니다.

값의 크기를 변경할 수 있습니다.

 

배열 크기 변경

배열로 작성한 변수와 슬라이스로 작성한 변수 크기를 변경해보겠습니다.

배열에 값을 추가하는 함수로 append를 사용합니다.

각각 append를 사용해 값을 추가해보겠습니다.

배열 append 예제

package main

import "fmt"

func main() {
	arr1 := [5]int{1, 2, 3, 4, 5}
	arr1 = append(arr1, 6)

	fmt.Println(arr1)
}

 

결과

./array.go:9:15: first argument to append must be slice; have [5]int
exit status 2
Process exiting with code: 1

 

배열인 경우에는 크기가 고정되어 있기 때문에 append를 사용해 값을 추가하려는 경우에 에러가 발생합니다.

슬라이스에 값을 추가해보겠습니다.

 

슬라이스 append 예제

package main

import "fmt"

func main() {
	slice1 := []int{1, 2, 3, 4, 5}
	slice1 = append(slice1, 6)

	fmt.Println(slice1)
}

 

결과

[1 2 3 4 5 6]

 

슬라이스는 크기가 동적으로 변경되기 때문에 append를 사용해서 값을 추가할 수 있습니다.

 

 

배열과 슬라이스 복사

배열과 슬라이스의 차이점으로 복사를 하는 경우입니다.

배열의 경우에는 변수를 다른 변수에 복사하면 같은 값을 가지 새로운 배열이 생깁니다.

그리고 원래 있던 배열과 복사한 배열은 메모리상에서 각각의 위치를 가지게 됩니다.

배열 복사 확인

package main

import "fmt"

func main() {
	a := [3]int{1, 2, 3}
	b := a

	// 메모리 위치 확인
	fmt.Println(&a[0]) // 0xc8200122e0
	fmt.Println(&b[0]) // 0xc820012300

	// 복사한 배열 값을 변경
	b[0] = 0
	fmt.Println(a) // [1 2 3]
	fmt.Println(b) // [0 2 3]
}

 

배열 변수 a를 복사해서 변수 b에 대입했습니다.

메모리 위치를 확인해보면 변수 a와 b는 참조하고 있는 위치가 다릅니다.

복사한 변수 b에 값을 변경하고 출력해보면 변수 b만 변경된 것을 알 수 있습니다.

주의점으로는 배열 변수를 복사하면 값뿐만 아니라 선언한 배열 크기도 복사됩니다.

이번에는 슬라이스를 복사해보겠습니다.

 

슬라이스 복사 확인

package main

import "fmt"

func main() {
	s1 := []int{1,2,3}
	s2 := s1

	// 메모리 위치 확인
	fmt.Println(&s1[0]) // 0xc8200122e0
	fmt.Println(&s2[0]) // 0xc8200122e0

	// 복사한 슬라이스 값을 변경
	s2[1] = 0

	// 같은 곳을 잠초하고 있기때문에 원본도 변경
	fmt.Println(s1) // [1 0 3]
	fmt.Println(s2) // [1 0 3]
}

 

슬라이스로 선언한 변수 s1 값을 s2에 대입했습니다.

메모리 위치를 확인해보면 같은 곳을 참조하고 있습니다.

복사한 변수 s2 값을 변경하고 출력을 해보면 원래 데이터인 s1 변수도 값이 변경된 것을 볼 수 있습니다.

배열인 경우에는 값을 복사하여 사용할 수 있지만 슬라이스는 값을 복사하여 사용할 경우 의도치 않은 문제를 만들 수 있습니다.

슬라이스 복사하는 방법은 아래를 참조해주세요.

Golang 슬라이스 복사 copy 함수 사용 방법
슬라이스에 저장해놓은값을 복사하고 싶은 경우가 있습니다. 단순히 새로운 변수에 대입해서 사용하게 되면 문제가 발생합니다. 이유는 메모리를 참조하고 있는 포인터까지 그대로 복사해오기 때문에, 복사해온 변수 또는 복사한 새로운 변수값을 변경하면 모두 변경이 돼버립니다. 슬라이스 복사하기 단순히 대입을 해서 사용하는 경우는 아래처럼 값이 모두 변경됩니다. 슬라이스 단순 대입 예제 package main import "fmt" func main() { slice := []int{0, 10, 20, 30} // 슬라이스 변수 slice값을 ...

 

정리

Go에서는 가변 배열인 슬라이스를 많이 사용합니다.

그리고 많이 사용은 안 하지만 배열도 존재합니다.

배열(array)은 고정, 슬라이스(slice)는 가변이라는 차이점을 가지고 있습니다.

그리고 더욱 중요한 차이로 참조 형태인지 아닌지입니다.

참조형인 슬라이스를 복사하거나 잘라서 사용하는 경우 단순히 새로운 변수에 대입해 사용하게 되면 의도치 않은 결과를 가져올 수 있으니 주의해서 사용해야 합니다.

댓글