본문 바로가기
프로그래밍

👨‍💻 [Go] Go 에서 기저 배열(underlying array) 이란 무엇이며, 어떻게 활용할 수 있나요?

by 밝음의기둥 2025. 1. 6.
반응형

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."


👨‍💻 안녕하세요, 윌리 프로젝트의 윌리 입니다.

Go 에서 기저 배열(underlying array) 이란 무엇이며, 어떻게 활용할 수 있는지 간략히 알아보았습니다.


질문 >

Go 에서 기저 배열(underlying array) 이란 무엇이며, 어떻게 활용할 수 있나요?

답변 >

Go에서 기저 배열(Underlying Array) 이란?

기저 배열은 슬라이스(Slice)가 참조하고 있는 실제 데이터가 저장된 배열을 의미합니다.

슬라이스는 기저 배열을 기반으로 작동하며, 슬라이스 자체는 기저 배열의 데이터에 대한 포인터와 함께 슬라이스의 길이(len)와 용량(cap) 정보를 포함하는 경량 구조입니다.


기저 배열의 주요 특징

  1. 슬라이스는 배열의 참조: 슬라이스는 데이터 자체를 복사하지 않고, 기저 배열을 공유합니다. 따라서 여러 슬라이스가 동일한 배열을 참조할 수 있습니다.
  2. 슬라이스 크기 조정: 슬라이스의 크기를 늘리거나 줄이면, 슬라이스가 참조하는 기저 배열의 다른 부분을 포함하거나 제외할 수 있습니다. 하지만 용량(cap)을 초과하여 추가 데이터를 삽입하면 새로운 기저 배열이 할당됩니다.
  3. 데이터 공유: 기저 배열을 참조하는 슬라이스를 통해 데이터가 공유되므로, 한 슬라이스에서 데이터를 변경하면 다른 슬라이스에도 영향을 미칩니다.

기저 배열과 슬라이스의 구조

슬라이스는 다음 세 가지 정보를 포함하는 데이터 구조입니다:

  • 포인터: 기저 배열의 시작 지점을 가리킵니다.
  • 길이(len): 슬라이스에 포함된 요소의 개수입니다.
  • 용량(cap): 슬라이스의 시작 위치부터 기저 배열의 끝까지의 요소 개수입니다.

기저 배열 활용 예제

1. 슬라이스와 기저 배열의 관계

package main

import "fmt"

func main() {
    arr := [5]int{1, 2, 3, 4, 5} // 기저 배열
    slice := arr[1:4]            // 기저 배열의 부분을 참조
    fmt.Println(slice)           // [2 3 4]

    slice[0] = 100               // 슬라이스를 통해 기저 배열 변경
    fmt.Println(arr)             // [1 100 3 4 5]
}


2. 슬라이스 크기 조정과 기저 배열

package main

import "fmt"

func main() {
    arr := [5]int{1, 2, 3, 4, 5}
    slice := arr[:2] // 길이 2, 용량 5
    fmt.Println(len(slice), cap(slice)) // 2, 5

    slice = slice[:4] // 길이를 늘려 용량 내의 영역 참조
    fmt.Println(slice) // [1 2 3 4]
}


3. 슬라이스의 데이터 공유

package main

import "fmt"

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

    slice1[2] = 100 // 기저 배열의 데이터를 변경
    fmt.Println(slice2) // [100 4 5]
}


새로운 기저 배열 생성

슬라이스의 용량을 초과하여 데이터를 추가하면, Go는 새로운 기저 배열을 생성하고 데이터를 복사합니다.

예제: 새로운 기저 배열 할당

package main

import "fmt"

func main() {
    slice := make([]int, 2, 3)
    slice[0], slice[1] = 1, 2
    fmt.Println(slice, len(slice), cap(slice)) // [1 2], 2, 3

    slice = append(slice, 3) // 용량 내에서 추가
    fmt.Println(slice, len(slice), cap(slice)) // [1 2 3], 3, 3

    slice = append(slice, 4) // 용량 초과, 새로운 배열 생성
    fmt.Println(slice, len(slice), cap(slice)) // [1 2 3 4], 4, 6
}


슬라이스의 독립 복사

슬라이스를 복사하여 기저 배열을 공유하지 않도록 하려면, 새 배열을 생성한 뒤 데이터를 복사해야 합니다.

package main

import "fmt"

func main() {
    original := []int{1, 2, 3}
    copySlice := make([]int, len(original))
    copy(copySlice, original)

    copySlice[0] = 100
    fmt.Println(original)   // [1 2 3]
    fmt.Println(copySlice)  // [100 2 3]
}


기저 배열 활용 시 주의 사항

  • 데이터 공유로 인한 부작용:
    • 기저 배열을 공유하는 여러 슬라이스 중 하나를 변경하면 다른 슬라이스에도 영향을 미칠 수 있습니다.
arr := [5]int{1, 2, 3, 4, 5}
s1 := arr[:3]
s2 := arr[2:]
s1[2] = 42
fmt.Println(s2) // [42 4 5]

  • 용량 초과 시 성능 비용:
    • 슬라이스에 데이터를 추가할 때 용량이 초과하면 새로운 배열이 할당되고 데이터가 복사됩니다. 이 과정은 성능에 영향을 줄 수 있습니다.
  • 슬라이스의 nil 상태:
    • 슬라이스가 nil인 경우, 길이와 용량이 모두 0이며, 이를 배열로 변환하거나 접근하려 하면 오류가 발생할 수 있습니다.

슬라이스와 기저 배열의 활용 요약

  • 슬라이스는 기저 배열을 기반으로 하여 데이터를 동적으로 관리할 수 있는 강력한 도구입니다.
  • 데이터 공유는 슬라이스의 효율성을 높이는 동시에, 잘못 사용하면 의도치 않은 부작용을 초래할 수 있으므로 신중하게 관리해야 합니다.
  • 새로운 기저 배열이 필요한 경우에는 make와 copy를 사용하여 데이터를 복사해 독립적인 슬라이스를 생성할 수 있습니다.


🎬 유튜브 채널 🎬

 

위로그@WiLog

📢 안녕하세요, 위로그@WiLog 시청자 여러분, 저는 윌리(Willee) 입니다. 📢 위로그@WiLog 는 자기계발을 목적으로 하는 채널 입니다. 📢 오늘도 즐겁게~ 자신을 위한 계발을 함께 해보아요~ d^_^b 📌

www.youtube.com

🎬 치지직 채널 🎬

 

위로그 채널 - CHZZK

지금, 스트리밍이 시작됩니다. 치지직-

chzzk.naver.com


반응형