언어 및 도구들 공부/Go

Go 포인터 공부 4 - 구조체 포인터로 접근하기

Dr.Mlem 2025. 4. 3. 16:17
import "fmt"

type Vertex struct {
    X int
    Y int
}

// 구조체 인스턴스 선언 방법
var (
    //① 일반적인 선언방식입니다. X가1, Y가 2로 초기화됩니다.
    v1 = Vertex{1, 2}
    //② X만 값을 지정해주고, Y는 int에  zero value로 설정됩니다.
    v2 = Vertex{X: 1}
    //③ X, Y모두 int에 zero value로 설정됩니다.
    v3 = Vertex{}
)

func main() {
    fmt.Println("v1.X값:", v1.X)
    v1.X = 4
    fmt.Println("v1.X = 4로 바꾼 v1.X값:", v1.X)
    
    //④ 구조체 포인터로도 구조체의 값을 바꿀 수 있습니다.
    var p  = &v1
    p.X = 10
    fmt.Println("포인터로 바꾼 v1.X값:", v1.X)
}

Q1. 위에서,
p.X=10 이 부분은, 원래 *p.X = 10 이어야 맞는 코드가 아닌가?



A1.

아주 예리해!

네 말대로 p는 포인터니까, **원래대로라면 (*p).X = 10**이 맞는 표현이야.

하지만 Go에서는 p.X = 10도 정상적으로 작동해, 그 이유를 정확히 설명해줄게.


✅ 요점 정리 먼저

Go에서는 포인터를 통해 구조체 필드에 접근할 때,
(*p).X = 10이라고 쓰지 않아도 p.X = 10으로 **자동 변환(dereferencing)**이 일어나서 동작함.


📌 왜 p.X = 10이 가능한가?

Go 언어는 개발자의 편의를 위해 다음과 같은 자동 dereferencing 규칙을 제공해:

구조체 포인터에서 필드에 접근할 때,
컴파일러가 자동으로 (*p).X → p.X로 변환해서 처리함


🔍 실제로 어떤 차이가 있나?

var p = &v1

p.X = 10       // ✅ 자동으로 (*p).X = 10 으로 처리됨
(*p).X = 20    // ✅ 원래 문법. 직접 역참조

fmt.Println(v1.X) // 출력: 20

→ 두 문법은 완전히 동일하게 동작하고, 컴파일러가 알아서 도와줘.


🧠 Go의 의도

Go는 “실용주의 언어”라서 C처럼 엄격하게 (*p).X 쓰라고 강요하지 않아.
오히려:

“아, 네가 포인터인 구조체에서 필드에 접근하려는 거지? 자동으로 역참조해줄게!”

이런 식으로 동작해.


✅ 결론

표현 의미 동작
(*p).X = 10 직접 역참조
p.X = 10 자동 역참조 ✅ (Go에서 허용)

그래서 네가 말한 "원래는 *p.X = 10이 아니냐"는 개념적으로 맞지만,
Go에서는 편하게 p.X = 10 써도 된다는 거야 😄

궁금하면 구조체 배열 포인터에서도 이런 방식 되는지도 테스트해볼 수 있어!
그것도 보고 싶어?

 
 
 
Q2.
그러니까 Go 에서는 구조체 내부의 값으로 접근할 때, 포인터로 접근하든 뭐로 접근하든 알아서 정리해준다는 말인가?
 
 
 
A2.
응! 너가 말한 요약은 아주 정확해!
조금 더 정확한 표현으로 정리해보자면:

✅ 정리: Go에서 구조체 필드 접근 시

구조체든 구조체 포인터든 .필드명으로 접근하면,
Go가 자동으로 역참조 처리를 해준다.

즉:

  • v.X → 구조체 값에서 필드 접근
  • p.X → 구조체 포인터에서 필드 접근 → Go가 자동으로 (*p).X로 처리

📌 왜 이렇게 했을까?

Go는 불필요한 문법적 복잡함을 줄이고,
개발자가 의도를 명확히 표현하는 데 집중하도록 하기 위해 이런 규칙을 제공해.

C나 C++은 이런 걸 직접 써야 해:

(*p).x // 혹은 p->x

Go는 그냥 p.x 쓰면 돼. 알아서 해석해줘.


🔍 예제로 다시 확인

type User struct {
    name string
}

func main() {
    u := User{name: "Alice"}
    up := &u

    fmt.Println(u.name)   // ✅ 구조체 값
    fmt.Println(up.name)  // ✅ 구조체 포인터도 동일하게 접근 가능 (자동 역참조)
}

✅ 핵심 요약

대상 접근 방식 작동 방식
구조체 변수 v.X 직접 접근
구조체 포인터 p.X (*p).X로 자동 변환됨
구조체 포인터 (*p).X 직접 역참조 (가능하지만 생략 가능)

👉 그래서 Go에선 .필드명 하나만 기억하면 돼.
그게 값이든 포인터든 걱정 없이 쓰면 Go가 알아서 처리해줘.

추가로 궁금한 예제나, 이 개념이 슬라이스, 맵, 구조체 배열에서 어떻게 적용되는지도 보여줄 수 있어!
궁금해? 😄

 

'언어 및 도구들 공부 > Go' 카테고리의 다른 글

빈 식별자, blank identifier, _  (0) 2025.04.04
Go) Unmarshal과 포인터  (0) 2025.04.04
Go 포인터 3  (0) 2025.03.29
Go 포인터 공부 2  (0) 2025.03.29
Go의 main 함수와 main 패키지  (0) 2024.12.26