GoLang - 배열과 슬라이스 ( array, slice )

dev_swan·2022년 11월 24일

Golang

목록 보기
7/9
post-thumbnail

배열

배열은 메모리 공간에서 연속된 위치에 있는 값 목록으로 자료구조 중 하나이며, Go에서는 같은 타입에 대해 여러개의 값을 담을 수 있습니다.

아래의 배열은 5개의 숫자를 받을 수 있는데, Go의 배열은 크기가 정해져있는 정적 배열입니다. 크기가 변할 수 있는 동적인것은 슬라이스라는 개념에서 다루어집니다.

package main

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

배열을 여러 줄로 사용하기 위해서는 맨 마지막요소에 콤마를 반드시 찍어주어야 합니다.

package main

func main() {
	runes := [5]rune{
		"A",
		"B",
		"C",
		"D",
		"E",
	}
}

제로 값 ( default value )

배열만 선언 해놓고 값을 할당하지 않은 경우에는 각 타입에 알맞는 제로값이 설정됩니다. 아래의 경우 int 타입의 제로값은 0이기 때문에 모든 원소가 0입니다.

package main

import "fmt"

func main() {
	var numbers [5]int

	for _, num := range numbers {
		/** -> 0, 0, 0, 0, 0 */
		fmt.Println(num)
	}
}

인덱스 제로 베이스

배열의 원소에 접근하기 위한 인덱스는 제로베이스로 0부터 시작하여 마지막 원소의 인덱스는 array.lenght - 1이 됩니다.

package main

import "fmt"

func main() {
	var numbers [5]int
	numbers[0] = 10
	numbers[3] = 40

	for _,num := range numbers {
		/** 10, 0, 0, 40, 0 */
		fmt.Println(num)
	}
}

슬라이스

슬라이스는 크기가 정해지지 않은 동적 배열입니다.

Go의 슬라이스의 특징으로는, 슬라이스는 그저 배열의 뷰일 뿐, 그 외에 다른 의미는 가지지 않는다는 점입니다. 슬라이스는 기존의 배열을 기반으로 만들어질 수도 있고, 자체적으로 내부 배열을 가질 수도 있습니다.

중요한 사항은 슬라이스는 내부적으로 배열을 기반으로 한다는 점입니다.

슬라이스는 배열과는 다르게 슬라이스를 생성하는 별도의 작업이 필요합니다. make() 빌트인 함수를 사용하여 슬라이스를 생성하고, 그 외에는 배열과 사용법이 같습니다.

아래의 슬라이스는 5개의 숫자 공간을 미리 확보해놓은 슬라이스를 생성합니다.

package main

func main() {
  numbers := make([]int, 5)
}

제로 값 ( default value )

make()를 사용하지 않고 타입만 있는 형태의 변수로 선언한 슬라이스의 제로 값은 null 입니다.

package main

import "fmt"

func main() {
	var numbers []int

	/** -> true */
	fmt.Println(numbers == nil)
}

여기서 중요한 사항은, nil 슬라이스에 대해 길이를 계산하거나 값을 새로 추가해도 에러가 발생하지 않고 길이가 0인 슬라이처럼 취급한다는 점입니다.

package main

import "fmt"

func main() {
	var numbers []int

	/** -> 0 */
	fmt.Println(len(numbers))
}

기존의 배열을 기반으로 슬라이스 만들기

이미 만들어진 배열을 기반으로 슬라이스를 만들 수 있습니다.

아래의 코드에서 numbers[1:4]의 의미는 인덱스 1을 포함하고 인덱스 4미만까지만 포함한다는 뜻입니다.

아래의 배열에서는 1,2,3의 인덱스 값을 가진 값들이 이에 해당합니다.

package main

import "fmt"

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

	for _, num := range numbers[1:4] {
    /** -> 1, 2, 3 */
		fmt.Println(num)
	}
}

또한 주의해야 하는 사항으로, 슬라이스를 변경하면 원본 배열도 바뀌고 원본 배열을 바꾸면 슬라이도 바뀝니다. 이는 그저 슬라이스가 배열의 일부분을 보여주는 것이기 때문입니다.

package main

import "fmt"

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

	s[0] = 100
	s[1] = 200

	/** [100 200 3] */
	fmt.Println(s)

	/** [0, 100, 200, 3, 4] */
	fmt.Println(numbers)
}

[1:4] 라는 형태에서, [1:]이 되면 인덱스 1에서 가장 마지막 인덱스까지를 의미하고, [:4]가 되면 가장 첫 인덱스에서 3까지를, 마지막으로 [:]가 되면 첫인덱스에서 끝까지를 의미하는데 이는 배열에서 슬라이스로 변환할 때 사용하기도 합니다.

내부 배열이 있는 슬라이스

슬라이스는 독립적으로 사용될 경우 내부 배열을 지니고 있습니다. 슬라이스 값을 추가할 때는 append()함수를 사용하는데, 이는 내부적으로 슬라이스의 내부 배열의 공간이 부족하면 새로운 배열을 만들고 복사하여 처리합니다. 이러한 처리 때문에 일부 문제나 버그가 발생할 수 있으므로 슬라이스에 값을 추가할 때는 똑같은 슬라이스에 재할당하는 것이 핵심입니다.

package main

import "fmt"

func main() {
	numbers := make([]int,0)
	
	for _, num := range [5]int{0,1,2,3,4} {
		numbers = append(numbers, num)
	}

	/** -> 0, 1, 2, 3, 4 */
	fmt.Println(numbers)
}

추가적으로, 기존의 배열에서 가져온 슬라이스에 append()를 통해 값을 추가하면 값이 추가된 인덱스의 값을 덮어씌워버립니다.

numbers[1:4]의 슬라이스에 값을 추가하게 되면 4번 인덱스에 값이 들어가게 되어 기존의 값 4는 500으로 덮어씌워지게 됩니다.

package main

import "fmt"

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

	/** 1, 2, 3 */
	fmt.Println(s)
	s = append(s, 500)

	/** 1, 2, 3, 500 */
	fmt.Println(s)
	/** 0, 1, 2, 3, 500 */
	fmt.Println( numbers)
}

참고자료

Go 언어를 공부하기 위한 자료 및 문서 정리


Go 언어 공부 GoGo~~! 엌ㅋㅋㅋㅋㅋㅋㅋ

0개의 댓글