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 값으로 초기화!