20200615
C 의 후계자 답게 Go 에도 포인터가 있습니다. 하지만 너무 겁먹을 필요는 없습니다.
C++ 처럼 포인터의 종류가 다양한 것도 아니고 C 처럼 포인터 연산을 하는 것도 아닙니다. Go 포인터는 그저 변수가 저장된 위치 (주소) 를 담는 역할에 충실합니다.
Go 포인터
변수(Variable) 은 값을 담는 저장소 조각입니다.
포인터 값(Pointer value)은 변수의 주소입니다.
따라서 포인터(Pointer)는 값이 들어있는 저장소 위치를 저장합니다.
모든 값이 주소를 가지는 건 아니지만, 모든 변수는 포인터 값을 가집니다.
포인터를 사용하면 변수의 이름을 몰라도 변수 값을 읽고 바꿀 수 있습니다.
모든 포인터의
영 값(zero value) 는 nil 입니다. 모든 변수는 주소를 가지기 때문에 포인터가 어떤 변수의 주소를 담고 있다면 nil 이 아니게 됩니다.
두 포인터가 같은 경우는 모두 같은 변수를 가리키거나 둘 다 nil 일때 뿐입니다.
1
2
3
4
5
6 | var p = f()
func f() *int {
v := 0
return &v
}
fmt.Println(f() == f()) // "false"
|
지역변수 v의 주소를 p에 담습니다. 지역 변수이지만 리턴 이후에도
p가 여전히 참조하고 있기 때문에 사라지지 않습니다.f를 호출할 때마다 다른 변수가 리턴됩니다.
아래 incr 함수는 p가 가리키는 변수의 값을 1 더하는 함수입니다.
1
2
3
4
5
6
7 | func incr(p *int) int {
*p++
return *p
}
v := 1
incr(&v) // v 는 2
fmt.Println(incr(&v)) // "3"
|
new 함수
새로운 변수를 만들 때 이름을 지정하지 않고 new를 이용해서 선언할 수 있습니다.
1
2
3
4 | p := new(int) // 새로운 이름 없는 int 변수를 만들고 그 주소를 p 에 저장
fmt.Println(*p) // p 가 가리키는 변수의 값 출력 "0"
*p = 2 // p 가 가리키는 변수의 값 변경
fmt.Println(*p) // "2"
|
이름 없는 변수는 영 값(zero value)을 가집니다.
new 함수가 특별할 것은 없습니다. 위에서 봤던 f 함수와 다른게 없습니다.
f 함수처럼 new를 호출할 때마다 다른 변수가 리턴됩니다.
new 함수는 키워드가 아니기 때문에, new 라는 이름의 변수나 함수를 만들어도 됩니다.