본문 바로가기
Language/Go

[Go] Slice, Pointer, Struct

by eess 2024. 6. 26.

 

Slice vs Array

  • Python, JS와 달리 Golang의 array는 정해진 길이가 있습니다.
// Array
foods := [3]string{"kimchi", "pizza", "pasta"}

for _, food := range foods {
    fmt.Println(food)
}
// 또는
for i := 0; i < len(foods); i++ {
    fmt.Println(foods[i])
}

> kimchi
> pizza
> pasta
  • slice는 가변 길이의 배열이다. 대괄호 안의 숫자를 지우면 slice가 됩니다. (JS의 array처럼)
  • slice에 요소를 추가할 때는 append 메서드를 사용하고 복사본으로 원본 slice를 업데이트 해줘야 합니다.
// Slice
foods := []string{"kimchi", "pizza", "pasta"}
fmt.Printf("%v\n", foods)
> kimchi
> pizza
> pasta

foods = append(foods, "icecream")  // 요소 추가
fmt.Printf("%v\n", foods)

> kimchi
> pizza
> pasta
> icecream

 

 

Pointer

  • Go는 개발자가 컴퓨터 메모리에 접근하게 해줍니다.
  • 아래와 같은 경우 a의 값을 변경해도 a의 값을 복사한 b에는 영향이 가지 않습니다. 
    • JS의 원시자료형과 마찬가지로, b에는 a의 값을 복사하여 독립적인 변수로 생성되기 때문입니다.
a := 2
b := a
a = 12
fmt.Println(b)  // 2

 

  • 변수 앞에 (&)를 붙이면 변수의 메모리 주소를 얻을 수 있습니다.
    • 아래의 코드에서 b는 a의 위치를 담은 포인터 변수가 됩니다. 이는 복사가 아니라 참조입니다!
    • 즉, a를 언제 업데이트하든 b에서 a의 값을 얻을 수 있다는 것입니다.
    • 포인터 변수에 저장된 메모리 주소가 가리키는 곳의 값을 얻으려면 포인터 변수 앞에 (*)을 붙이면 됩니다.
a := 2
b := &a
a = 50
fmt.Println(b, &a) // 0x140000a6018 0x140000a6018
fmt.Println(*b) // 50

 

Struct & Receiver

  • 다른 언어에서의 class와 method를 Golang에서는 struct와 receiver 함수로 볼 수 있습니다.
  • 함수 이름 앞에 struct 이름을 명시해주면, 이는 해당 struct 타입의 변수에만 유효한 receiver 함수가 됩니다.
  • NodeJS에서는 export를 반드시 명시해줘야 하는 것과 달리, Go에서는 대문자로 시작하도록 작성하면 자동으로 Export가 됩니다.
    • 이 점을 활용하여 struct의 필드는 소문자로 작성해서 외부에서 직접 수정하지 못하도록 하고, receiver 함수를 통해 접근하게 만들 수 있습니다. (a.k.a 캡슐화)
  • 주의할 점은 receiver 함수에 수정이 필요한 경우 receiver 포인터 함수로 설정해주어야 합니다.
    • struct 타입 앞에 (*)을 붙이지 않으면 struct를 복사한 값에 대해 receiver 함수가 실행됩니다.

Value Receiver

  • receiver 함수의 타입이 struct의 값인 경우, struct의 값을 복사하여 함수 내에서 사용합니다.
  • 함수 내에서 struct의 필드를 변경하더라도 원본 struct에는 영향을 미치지 않습니다.
  • 따라서, struct의 필드 수정이 필요하지 않은 경우에 사용합니다.

Pointer Receiver

  • receiver 함수의 타입이 struct의 포인터인 경우, struct의 메모리 주소를 통해 원본 struct에 직접 접근합니다.
  • 함수 내에서 struct의 필드를 변경하면 원본 struct가 수정됩니다.
  • 따라서, struct의 필드 수정이 필요한 경우 사용합니다.
// struct
type Person struct {
    name string
    age int
}

// value receiver function
func (person Person) SayHello() {
    fmt.Printf("Hello My name is %s and I'm %d", person.name, person.age)
}

// pointer receiver function
func (person *Person) SetDetails(name string, age int) {
    person.name = name
    person.age = age
}

func main() {
    person := Person{}
    person.SayHello()
    person.SetDetails("confident-dev", 12);
    fmt.Println(person)  // confident-dev  12
}

 

참고

'Language > Go' 카테고리의 다른 글

[Go] Go 프로젝트 설정  (0) 2024.06.24