[Go 언어] 35. 배열의 대입 연산은 값 복사, 슬라이스는 참조

안녕하세요. 언제나 휴일, 언휴예요.

이번에는 배열과 슬라이스의 차이점 중에 개발자가 실수하기 쉬운 대입 연산을 알아보기로 해요.

선언할 때와 인덱스 연산으로 원소에 접근하는 것은 배열과 슬라이스의 공통점이예요. 그런데 대입 연산에서는 차이가 있어요. 배열끼리 대입 연산을 하면 원소 값을 모두 복사합니다. 하지만 슬라이스는 내부적으로 참조 형식이어서 같은 개체를 참조할 뿐이예요.

예를 들어 배열 arr1에 1, 2, 3 값의 원소를 갖고 있을 때 arr2에 대입하면 arr2 배열도 1, 2, 3 값을 갖는 상태로 변해요. 이 때 arr2[0]=8 연산을 수행하면 arr2는 예상처럼 원소 값은 8, 2, 3으로 변해요. 하지만 arr1은 arr2와 독립적이어서 여전히 1, 2, 3 원소 값을 갖고 있어요.

하지만 슬라이스 s1에 1, 2, 3 값의 원소를 갖고 있을 때 s2에 대입하면 두 개의 변수 s1과 s2는 1, 2, 3 값을 갖는 같은 슬라이스 개체를 참조한답니다. 이 때 s2[0] = 8 연산을 수행하면 두 개의 변수로 참조하는 개체는 같은 슬라이스 개체이기 때문에 원소 값은 8, 2, 3이예요.

다음은 이를 확인하는 간단한 예제 코드예요.

//배열과 슬라이스 대입 연산 비교
package main

import "fmt"

func main() {
    //배열
    var arr1 [3]int = [3]int{1, 2, 3}
    var arr2 [3]int

    fmt.Print("before arr1 :")
    fmt.Println(arr1)
    fmt.Print("before arr2 :")
    fmt.Println(arr2)

    arr2 = arr1

    arr2[0] = 8
    fmt.Print("after arr1 :")
    fmt.Println(arr1)
    fmt.Print("after arr2 :")
    fmt.Println(arr2)

    //슬라이스
    var s1 []int = []int{1, 2, 3}
    var s2 []int

    fmt.Print("before s1 :")
    fmt.Println(s1)
    fmt.Print("before s2 :")
    fmt.Println(s2)

    s2 = s1

    s2[0] = 8
    fmt.Print("after s1 :")
    fmt.Println(s1)
    fmt.Print("after s2 :")
    fmt.Println(s2)

}

실행 결과는 다음과 같아요.

before arr1 :[1 2 3]
before arr2 :[0 0 0]
after arr1 :[1 2 3]
after arr2 :[8 2 3]
before s1 :[1 2 3]
before s2 :[]
after s1 :[8 2 3]
after s2 :[8 2 3]