C언어와 닮은 언어이기 때문에 pointer 개념이 사용된다.
: 메모리 주소를 값으로 갖는 타입
var a int //변수 a는 메모리 공간의 100번지(변수의 시작주소)를 '가리키고' 있다.
var p *int //포인터 변수 선언
p = &a //a의 메모리 주소를 포인터 변수 p에 대입
*p = 20
ex)
func main() {
var a int = 500
var p *int
p = &a
fmt.Printf("p의 값: %p\n", p) //p의 값: 0xc0000be000
fmt.Printf("p가 가리키는 메모리의 값: %d\n", *p) //p가 가리키는 메모리의 값: 500
*p = 100 //a = 100과 같은 것
fmt.Printf("a의 값: %d\n", a) //a의 값: 100
}
var p *int // p = nil
if p != nil {
// p가 nil이 아닌, 정상적인 메모리 주소를 가리키고 있을 때 실행
}
type Data struct {
value int
data [200]int
}
func ChangeData(arg Data) {
arg.value = 999
arg.data[100] = 999
}
func main() {
var data Data
ChangeData(data)
fmt.Printf("value = %d\n", data.value) //value = 0
fmt.Printf("data[100] = %d\n", data.data[100]) //data[100] = 0
}
999라는 값을 대입했음에도 불구하고 0(default값이 나오는 이유)!
go언어에서 대입연산자 기능 : r-value의 메모리 공간크기 만큼의 l-value공간에 복사한다
따라서 복사한다는 것은, 결국 양쪽의 메모리 크기는 같지만 엄연히 다른 공간이라는 뜻.
그렇기 때문에 위의 예제에서
ChangeData(data)로 함수를 호출할 때, 전달되는 data는 실제 main함수 내에서 선언한 data 구조체가 아닌, 복사본이 전달되는 것이다.
ChangeData 함수가 실행되는 동안에는 복사본구조체의 값을 999로 바꾸는 것이기 때문에, 함수에서 main함수로 돌아온 뒤 원본 구조체의 값을 출력하면 변함없이 0이 나오는 것이다.
이를 해결하기 위해서는 포인터만 도입하면 된다.
값을 복사하는 것이 아닌, 주소값을 복사하는 것이다.
type Data struct {
value int
data [200]int
}
func ChangeData(arg *Data) { // *추가!
arg.value = 999
arg.data[100] = 999
}
func main() {
var data Data
ChangeData(&data) // &추가!
fmt.Printf("value = %d\n", data.value) //value = 0
fmt.Printf("data[100] = %d\n", data.data[100]) //data[100] = 0
}
여기서 짚고 넘어가야할 사항,
그렇다면 ChangeData 함수 내부문들은 아무것도 고치지 않아도 되는가?
arg가 Data구초제타입의 변수였다가, Data구조체타입 변수의 주소값을 가지는 포인터 변수로 바뀌었는데, arg.value, arg.data[100]는 그대로 사용해도 될까?
=> Go언어에서는 이를 허용한다!
정석대로 사용하자면 (*arg).value, (*arg,data[100])으로 변경해야,
arg라는 포인터변수가 갖는 주소값이 가리키는 메모리 공간 내의 값에 접근하게 되는데,
그냥 포인터변수명 뒤에 점만 찍으면 알아서 의미해석을 해준다 ㅎㅎ
익숙한 형태의 구조체 포인터 초기화
var data Data
var p *Data = &data
-> 이런 방식으로 한줄로 줄일 수 있다.
var p *Data = &Data{}
: 메모리에 할당된 데이터의 실체
1. "Data 인스턴스 하나가 만들어졌고, 포인터 변수 p가 가리킨다"
var p *Data = &Data{}

var p1 *Data = &Data{}
var p2 *Data = p1
var p3 *Data = p1

var data1 Data
var data2 Data = data1
var data3 Data = data1

: 구조체를 생성할 때 사용할 수 있다
p1 := &Data{}
var p2 = new(Data)
1과 2는 같은 기능을 한다.
1은 중괄호 내에 초기값을 넣을 수 있다.
ex : &Student{"Lydia", 23}
2는 초기값을 넣을 수 없다. 무조건 default 값으로 초기화!