- 함수를 호출할 때 인자를 가질 경우 인자는 함수로 복사된다.
func zero(x int) {
x=0
}
func main() {
x := 5
zero(x)
fmt.Println(x) // x is still 5
}
- 위의 프로그램에서 zero 함수는 원본 x 변수를 수정하지 못한다. 하지만 그렇게 하고 싶다면? 포인터를 사용하면 된다.
func zero(xPtr *int) {
*xPtr = 0
}
func main() {
x := 5
zero(&x)
fmt.Println(x) // x is 0
}
- 포인터는 값 자체가 아니라 값이 저장된 메모리 위치의 참조값이다. 포인터를 사용함으로서 zero 함수는 원본 변수를 수정할 수 있다.
*와 &
- 고에서 포인터는 *로 표현한다. 그리고 zero 함수에서 xPtr은 int를 가리킨다.
- *는 포인터 변수를 dereference하는 데에도 사용된다. 포인터를 역참조하는 것은 우리에게 포인터가 가리키는 값을 접근할 수 있도록 한다. 우리가 *xPtr = 0 이라고 적는다면 우리는 int 0 을 xPtr이 참조하는 메모리 영역에 저장해라고 말하는 것과 같다. 만약 우리가 xPtr = 0를 사용한다면 컴파일러는 xPtr이 int가 아니라 *int라는 에러를 던질 것이다.
- &는 변수의 주소값을 찾을 때 사용한다. &x는 *int를 반환한다. 왜냐하면 x가 int기 때문이다. 이것은 원본 변수를 수정할 수 있도록 허락한다. main의 &x와 zero의 xPtr은 같은 메모리 주소를 참조한다.
new
- 포인터를 가져오는 다른 방법은 new를 이용하는 것이다 .
func one(xPtr *int) {
*xPtr = 1
}
func main() {
xPtr := new(int)
one(xPtr)
fmt.Println(*xPtr) // x is 1
}
- new는 하나의 타입을 인자로 받는다. 그리고 그 타입의 값이 들어가기에 충분한 메모리를 할당한다. 그리고 그것의 포인터를 돌려준다.
- 몇몇 프로그래밍 언어에서 new와 &는 많이 다르다. 그래서 new로 생성된 것을 제거할 때에 많은 주의를 기울이기도 한다. 하지만 고는 다르다. 가비지 컬렉터가 아무것도 참조하지 않는 것은 자동적으로 치운다.