고랭(Go) 슬라이스 전달과 append 함수의 비밀 파헤치기

고랭(Go) 슬라이스 전달과 append 함수 깊이 이해하기

고랭(Go)에서 슬라이스(slice)는 배열(array)에 대한 동적인 인터페이스(interface)를 제공하는 강력하고 유연한 자료 구조입니다.

슬라이스(slice)를 함수에 전달하는 방법과 append 함수를 효과적으로 사용하는 방법을 이해하는 것은 효율적인 고랭(Go) 프로그래밍에 매우 중요합니다.

핵심 요약

  • 슬라이스(slice)를 함수에 전달하면 슬라이스 헤더(slice header)가 복사되지만, 원본과 복사본 모두 동일한 내부 배열(underlying array)을 가리킵니다.

  • 함수 내에서 슬라이스(slice)를 수정하면 append가 새로운 메모리 할당을 유발하지 않는 한 원본에도 영향을 미칩니다.

  • append 함수는 기존 용량(capacity)을 초과하면 새로운 배열(array)을 할당할 수 있습니다.

함수에 슬라이스 전달하기

고랭(Go)에서 함수에 슬라이스(slice)를 전달할 때, 여러분은 내부 배열(underlying array) 자체가 아니라 슬라이스 헤더(slice header)의 복사본을 전달하는 것입니다.

이는 함수가 자신만의 슬라이스 헤더(slice header) 복사본(내부 배열을 가리키는 포인터, 길이(length), 용량(capacity) 포함)을 받지만, 원본 슬라이스(slice)와 함수가 받은 복사본 슬라이스(slice) 모두 동일한 내부 배열(underlying array)을 가리킨다는 것을 의미합니다.

결과적으로, 함수 내에서 슬라이스(slice)의 요소를 수정하면 원본 슬라이스(slice)에도 영향을 미칩니다.

하지만, 함수 내에서 슬라이스(slice) 자체를 수정하는 경우, 예를 들어 append 함수를 사용하여 새로운 요소를 추가하는 경우에는 이야기가 달라집니다.

만약 기존 배열(array)의 용량(capacity)이 충분하지 않다면, 함수 내의 슬라이스 헤더(slice header) 복사본은 새로운 내부 배열(underlying array)을 가리키도록 변경될 수 있습니다.

이 경우, 원본 슬라이스(slice)는 변경되지 않은 상태로 남아있게 됩니다.

이러한 수정 사항을 원본 슬라이스(slice)에 반영하려면, 함수에서 수정된 슬라이스(slice)를 반환(return)하여 다시 할당하거나, 슬라이스(slice)에 대한 포인터(pointer)를 함수에 전달해야 합니다.

예시: 함수 내에서 슬라이스 수정하기

package main

import "fmt"

func modifySlice(s []int) {
    // 첫 번째 요소를 수정합니다; 원본 슬라이스에도 영향을 미칩니다.<br /><br />
    s[0] = 10
    // 새로운 요소를 추가합니다; 용량(capacity)이 초과되면 원본 슬라이스에 영향을 주지 않을 수 있습니다.<br /><br />
    s = append(s, 20)
    fmt.Println("함수 내부:", s)
}

func main() {
    nums := []int{1, 2, 3}
    modifySlice(nums)
    fmt.Println("함수 외부:", nums)
}

 
출력 결과:

Inside function: [10 2 3 20]
Outside function: [10 2 3]

 

이 예제에서 s[0]의 수정은 원본 슬라이스(slice) nums에 영향을 미칩니다.

하지만 append 작업은 원본 배열(array)의 용량(capacity)을 초과할 경우 s가 새로운 내부 배열(underlying array)을 가리키게 만들 수 있으며, 이 경우 함수 외부의 nums는 변경되지 않은 채로 남게 됩니다.

함수 사용하기

고랭(Go)의 내장 함수(built-in function)인 append는 슬라이스(slice)의 끝에 요소를 추가하는 데 사용됩니다.

만약 슬라이스(slice)의 용량(capacity)이 충분하다면, 요소들은 기존 배열(array)에 추가됩니다.

만약 용량(capacity)이 충분하지 않다면, 새로운 배열(array)이 할당되고 요소들은 그 새로운 배열(array)에 추가됩니다.

append 함수는 업데이트된 슬라이스(slice)를 반환하며, 이 반환된 슬라이스(slice)는 새로운 내부 배열(underlying array)을 가리킬 수 있습니다.

문법:

newSlice := append(originalSlice, elements...)

 

예시: 슬라이스에 요소 추가하기

package main

import "fmt"

func main() {
    nums := []int{1, 2, 3}
    // nums 슬라이스에 4와 5를 추가하고, 결과를 다시 nums에 할당합니다.<br /><br />
    nums = append(nums, 4, 5)
    fmt.Println(nums) // 출력: [1 2 3 4 5]
}

 

예시: 슬라이스에 다른 슬라이스 이어붙이기

하나의 슬라이스(slice)에 다른 슬라이스(slice)를 이어붙이려면, 두 번째 슬라이스(slice)의 요소들을 펼치기 위해 ... 연산자(operator)를 사용합니다.

package main

import "fmt"

func main() {
    slice1 := []int{1, 2, 3}
    slice2 := []int{4, 5, 6}
    // slice1에 slice2의 모든 요소를 이어붙입니다.<br /><br />
    slice1 = append(slice1, slice2...)
    fmt.Println(slice1) // 출력: [1 2 3 4 5 6]
}

 

이 예제에서 slice2...slice2의 요소들을 개별 요소로 풀어주며, append 함수는 이 요소들을 slice1에 추가합니다.

자주 묻는 질문 (FAQs)

(원문에는 이 헤더만 있고 내용은 없었습니다.

필요하다면 관련 질문과 답변을 추가할 수 있습니다.

)

핵심 요약 다시 보기

  • 슬라이스(slice)를 함수에 전달하면 슬라이스 헤더(slice header)가 복사되지만, 원본과 복사본 모두 동일한 내부 배열(underlying array)을 가리킵니다.

  • 함수 내에서 슬라이스(slice)의 요소를 수정하면 원본 슬라이스(slice)에도 영향을 미칩니다.

  • 함수 내에서 슬라이스(slice)에 요소를 추가(append)할 때, 내부 배열(underlying array)의 용량(capacity)이 초과되면 append가 새로운 배열(array)을 할당할 수 있으므로 원본 슬라이스(slice)에 영향을 주지 않을 수 있습니다.

  • 함수 내에서 슬라이스(slice)에 대한 변경 사항(특히 append로 인한 재할당 가능성)을 원본에 확실히 반영하려면, 수정된 슬라이스(slice)를 반환(return)하여 다시 할당하거나 슬라이스(slice)에 대한 포인터(pointer)를 전달해야 합니다.

이러한 동작 방식을 이해하는 것은 고랭(Go)에서 슬라이스(slice)를 효과적으로 다루는 데 필수적입니다.