주소 연산자(&)로 메모리 주소 할당
변수 앞에 주소 연산자(&)를 붙이면 변수의 메모리 주소를 알아낼 수 있고, 알아낸 메모리 주소를 포인터 변수에 할당해서 사용할 수 있다.
var p *int i := 1 p = &i fmt.Println(i) // 1 fmt.Println(&i) // 0x1043617c fmt.Println(*p) // 1 fmt.Println(p) // 0x1043617c
이 코드에서 볼 수 있듯이 int 타입인 변수 i와 포인터 변수 p는 동전의 양면과 같다. i는 값을 갖고 있고 p는 i의 주소를 갖고 있다. i에 & 연산자를 붙이면 주소를 알아낼 수 있고, p에 * 연산자를 붙이면 값을 알아낼 수 있다. 즉, i는 *p와 같고 &i는 p와 같다. 그래서 *p를 int 타입 변수처럼 사용할 수 있다.
var p *int var pp **int i := 1 p = &i pp = &p fmt.Println(i, *p, **pp) // 1 1 1 i += 1 fmt.Println(i, *p, **pp) // 2 2 2 *p++ fmt.Println(i, *p, **pp) // 3 3 3 **pp++ fmt.Println(i, *p, **pp) // 4 4 4
선언과 동시에 초기화할 수도 있다.
type rect struct{ w, h float64 } var i int = 1 var p *int = &i var s *rect = &rect{1, 2} fmt.Println(p) fmt.Println(s)
실행 결과
0x82000a260 &{1 2}
구조체 포인터를 출력하면 포인터가 가리키는 값과 포인터인 것을 나타내기 위해 &{1 2}처럼 주소 연산자(&)를 함께 출력한다(구조체는 4장 객체 지향 프로그래밍에서 설명한다)
일반 변수와 마찬가지로 선언과 동시에 값을 할당하는 경우 타입을 생략할 수 있다.
var p1 = &i var s1 = &rect{1, 2} s2 := &rect{1, 2} p2 := &i