Go) 포인터 자동 역참조
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{} 방식과의 차이나, 구조체 리터럴 초기화도 궁금하다면 더 알려줄게! 😊