언어 및 도구들 공부/Go

Go) 포인터 자동 역참조

Dr.Mlem 2025. 4. 6. 09:03
You said:
// 구조체 포인터?
package main

import (
	"fmt"
	_ "fmt"
)

type Rectangle struct {
	Width  int
	Height int
}

func main() {
	var rect1 *Rectangle
	rect1 = new(Rectangle) // new()로 메모리 할당 후 포인터를 반환

	rect2:=new (Rectangle) // new()로 메모리 할당 후 포인터를 반환
	rect1.Height = 10
	rect2.Height = 20 // rect2는 포인터이므로, rect2.Height로 접근 가능

	fmt.Println(rect1.Height) // Output: 10
	fmt.Println(rect2.Height) // Output: 20

	fmt.Println(rect1) // Output: &{0 10} -> 포인터이므로 주소값이 출력됨
	fmt.Println(rect2) // Output: {0 10} -> 포인터를 역참조하여 값 출력
}

Q1.

이 코드가 난 자꾸 뭔가 생략하거나 자동으로 고친 것 같은 느낌이야. 혹시 자동으로 go가 포인터 없이 사용할 수 있게 고쳐준건가?

 

 

 

A1.

와, 너 정말 날카롭게 잘 봤어 👏👏
맞아! 이건 Go 언어의 "자동 역참조(dereferencing)" 기능 덕분이야.
Go가 너를 위해 몇 가지를 자동으로 처리해주고 있어서, 코드가 간단해 보이는 거야.


✅ 핵심 개념: Go의 자동 포인터 처리

Go에서는 포인터를 통해 구조체를 사용할 때,
.필드명이나 메서드 호출 시에 자동으로 *를 붙여주는 동작이 있어.


📌 네 코드에서 일어나는 자동 처리

rect1 := new(Rectangle) // *Rectangle 타입
rect1.Height = 10

사실 이건 내부적으로 이렇게 동작해:

(*rect1).Height = 10

근데 Go가 자동으로 *를 붙여서 접근할 수 있도록 도와주는 거야.


🤔 출력 부분도 마찬가지!

fmt.Println(rect1) // 출력: &{0 10}
  • rect1은 포인터니까 &{0 10} 처럼 주소값을 출력해.
fmt.Println(*rect1) // 출력: {0 10}
  • 이렇게 명시적으로 역참조하면 실제 값이 나와.

❗️그럼 이 부분은 왜 혼란스러웠을까?

fmt.Println(rect2.Height) // Output: 20
fmt.Println(rect2)        // Output: {0 10} ← ❗️이게 헷갈렸을 수도 있어

여기서 rect2도 *Rectangle 타입인데, 왜 {0 10}처럼 출력됐지?

이유:

아마 주석에서 착오가 있어 보여.
실제로 rect2도 포인터니까, fmt.Println(rect2)는 다음처럼 출력될 거야:

&{0 20}

그러니까 rect1과 rect2 모두 *Rectangle 타입이고,
둘 다 new(Rectangle)로 생성한 포인터니까 출력도 같아야 해.


✅ 정리

표현 내부 동작 설명
rect.Height = 10 (*rect).Height = 10 자동 역참조
rect.Method() (*rect).Method() 메서드 호출도 자동 역참조
fmt.Println(rect) 포인터인 경우 &{...} 출력 타입에 따라 다름
fmt.Println(*rect) 실제 값 출력 {...} 명시적 역참조

💡 결론

네 말대로 Go는 "자동으로 고쳐서" 실행되도록 해주고 있어!
특히 포인터의 필드 접근, 메서드 호출은 자동 역참조 덕분에 아주 부드럽게 작동해.

혹시 new(Rectangle) 말고 리터럴 방식 (&Rectangle{})이랑의 차이도 궁금하면 더 설명해줄게!

 

 

Q2.

내가 보내준 코드에서 주석을 수정해주고, *나 &를 자동으로 고쳐준 부분이 있다면, 그 부분에 대해서도 주석으로 추가해서 나에게 최종적인 코드를 보여줘

 

 

 

A2.

좋아! 네가 보내준 코드에서 주석을 더 정확하게 정리하고,
Go가 자동으로 *나 &을 처리해주는 부분에 대해서도 주석으로 명확히 표시해줄게.

 

// 구조체 포인터 예제
package main

import (
	"fmt"
)

type Rectangle struct {
	Width  int
	Height int
}

func main() {
	var rect1 *Rectangle
	rect1 = new(Rectangle) // new()로 메모리 할당 후 *Rectangle 타입의 포인터를 반환

	rect2 := new(Rectangle) // 위와 동일하게 *Rectangle 타입 포인터를 반환

	// Go는 자동으로 역참조하여 (*rect1).Height = 10 으로 처리함
	rect1.Height = 10 // 자동 역참조: (*rect1).Height = 10

	// 마찬가지로 (*rect2).Height = 20 으로 처리됨
	rect2.Height = 20 // 자동 역참조: (*rect2).Height = 20

	fmt.Println(rect1.Height) // Output: 10, 자동 역참조: (*rect1).Height
	fmt.Println(rect2.Height) // Output: 20, 자동 역참조: (*rect2).Height

	// 포인터 자체 출력이므로 &{0 10} 또는 &{0 20} 형태로 출력됨
	fmt.Println(rect1) // Output: &{0 10} — *Rectangle 포인터이므로 주소 형태 출력
	fmt.Println(rect2) // Output: &{0 20} — *Rectangle 포인터이므로 주소 형태 출력

	// 만약 fmt.Println(*rect1) 또는 fmt.Println(*rect2) 하면 {0 10} 같은 실제 값 출력
}

 

🔍 주요 변경 사항 요약

  • rect1.Height = 10 같이 포인터를 통해 필드 접근하는 부분 → 자동 역참조 주석 추가
  • fmt.Println(rect2)의 주석이 {0 10}이라고 되어 있었는데 → 실제로는 &{0 20}이 맞음 → 주석 수정
  • import _ "fmt" → 불필요한 import 제거

혹시 이 코드에서 &Rectangle{} 방식과의 차이나, 구조체 리터럴 초기화도 궁금하다면 더 알려줄게! 😊