숏컷 코드
count := 3
ptr := &count
*ptr = 4
fmt.Println(count) // 4Go pointer는 값의 주소를 넘겨서 같은 값을 수정하거나 큰 값을 복사하지 않기 위한 표면입니다.
문법
&는 주소를 얻는다
count := 3
ptr := &countptr의 타입은 *int입니다. int 값을 직접 담은 것이 아니라 int 값이 있는 주소를 담습니다.
*는 pointer가 가리키는 값을 읽거나 쓴다
fmt.Println(*ptr)
*ptr = 10*ptr은 pointer가 가리키는 실제 값입니다. nil pointer를 역참조하면 panic이 납니다.
var ptr *int
// fmt.Println(*ptr) // panic함수 인자는 기본적으로 값으로 전달된다
func Rename(user User) {
user.Name = "new"
}이 함수는 User 값을 복사해서 받습니다. 호출자 쪽 값을 바꾸려면 pointer를 받아야 합니다.
func Rename(user *User) {
user.Name = "new"
}slice, map, channel은 값으로 전달해도 내부 데이터나 런타임 구조를 공유합니다. "값으로 전달된다"는 말이 항상 깊은 복사를 뜻하지는 않습니다.
수신자
값을 바꾸는 method는 pointer receiver가 맞다
func (u *User) Rename(name string) {
u.Name = name
}method가 receiver 내부 상태를 바꾸면 pointer receiver를 씁니다.
작은 immutable 값은 value receiver도 자연스럽다
func (p Point) Distance() float64 {
return math.Hypot(p.X, p.Y)
}작고 변경하지 않는 값은 value receiver가 읽기 쉽습니다. 다만 같은 타입의 method receiver는 가능하면 한쪽으로 일관되게 맞추는 편이 좋습니다.
선택 기준
| 상황 | 먼저 떠올릴 선택 |
|---|---|
| 값을 수정해야 함 | pointer |
| nil 가능성을 표현 | pointer |
| 큰 구조체 복사 회피 | pointer |
| 작은 값 읽기 전용 | value |
| method가 상태 변경 | pointer receiver |
| method가 계산만 수행 | value receiver 검토 |
주의할 점
pointer를 쓰면 수정 가능성과 nil 가능성이 같이 생깁니다. 단순히 "빠를 것 같다"는 이유만으로 모든 값을 pointer로 바꾸면 코드가 더 위험해질 수 있습니다. 값의 소유권, 변경 여부, nil을 의미 있게 다룰지부터 먼저 확인해야 합니다.
참고 링크
3 sources