ポインタ
変数に値を格納するとき、コンピュータはメモリの特定の位置(アドレス)を指定してそこに値を保持する。
Go言語では、この値を格納している場所を指す「ポインタ」を操作することができる。
ポインタでメモリ上のアドレスを参照する
まず、int型の変数nを宣言して100を代入し、変数nを出力する。
次に変数nに&をつけて実行する。すると、「0x14--------」(値は適当)と変数nのポインタ(メモリのアドレス)が表示される
var n int = 100
fmt.Println(n)
fmt.Println(&n)
//以下のように出力される
100
0x14--------
続いて変数pを「var p *int」と宣言し、&nを代入する。「*int」は、int型の値のポインタをという意味。
変数pを表示すると、先ほどと同様にメモリのアドレスが表示される。このようなポインタを持つ変数は、ポインタ変数と呼ばれる。
var n int = 100
fmt.Println(n)
fmt.Println(&n)
var p *int = &n
fmt.Println(p)
//以下のように出力される
100
0x14--------
0x14-------- (変数pのメモリのアドレスが表示される)
アドレスがさすメモリの中身を取得したい場合は、ポインタ変数に*をつける。
var n int = 100
fmt.Println(n)
fmt.Println(&n)
var p *int = &n
fmt.Println(p)
fmt.Println(*p)
//以下のように出力される
100
0x14--------
0x14--------(変数pのメモリのアドレスが表示される)
100(メモリの中身が表示される)
var n int = 100では、メモリの「0x0004」というアドレスに100という値を代入している。var p *int = &nでは、アドレス「0x0010」に「0x0004」というアドレスを代入している。したがって、fmt.Println(p)では「0x0004」が表示され、fmt.Println(*p)でポインタの中身を表示させると、100という値が表示される。
関数でポインタを受け取る
関数の引数に値もしくは値が入った変数をこれまで指定していたが、ポインタを引数に指定することもできる。
int型の引数xを受け取るone関数を作り、その中でxに1を代入する。main関数で宣言した変数nを、one関数の引数に指定して呼び出す。その後、nの値を表示すると、one関数で引数の値を1にしたのに100が表示される
func one(x int) {
x = 1
}
func main() {
var n int =100
one(n)
fmt.Println(n)
}
//以下が表示される
100
これはone関数が受け取るのは変数nそのものではなくて、変数nの値を受け取る。このため、関数の中で値に1を代入しても、main関数で宣言した変数nには影響が出ない。
変数nの値をone関数内で変更したい場合は、ポインタを渡す必要がある。まず、one関数の引数を「x int」とを付けて、ポインタとして受け取るようにする。
one関数の処理の中では、引数のポインタがさす実体(変数の値)を変更したいので「*x = 1」とかく。
また、引数がポインタ型になったので、main関数内のone関数を呼び出すときの引数も(&n)に変更する。
func one(x *int) { //ポインタの変数xを引数にする
*x = 1 //変数x(ポインタ)がさす実体に1を代入する
}
func main() {
var n int =100
one(&n) //&nのアドレスをone関数に渡す
fmt.Println(n)
}
//以下が表示される
1
変数のアドレスと中身を表示する
&と*を使って、変数のアドレスを表示したり、アドレスが指す実体を表示したりしてみる。
int型の値が格納された変数nについて、アドレスを見るためには「&n」と書く。
func main() {
var n int = 100
one(&n)
fmt.Println(n)
fmt.Println(&n)
}
//以下のように出力される
1
00140001120018(アドレスが出力される)
&nのアドレスの中身を見るためにはさらに「」をつけて「&n」と書く。
func main() {
var n int = 100
one(&n)
fmt.Println(n)
fmt.Println(*&n)
}
//以下のように出力される
1
1(アドレスの中身が出力される)
さらにアドレスの中身のアドレスを見るためには「&*&n」と書く。
func main() {
var n int = 100
one(&n)
fmt.Println(n)
fmt.Println(&*&n)
}
//以下のように出力される
1
0x14000113018(アドレスが出力される)
学習に使用した教材
・『入門】Golang基礎入門 + 各種ライブラリ + 簡単なTodoWebアプリケーション開発(Go言語)』M.A EduTech
https://www.udemy.com/course/golang-webgosql/?utm_medium=udemyads&utm_source=bene-msa&utm_campaign=responsive&utm_content=top-1&utm_term=general&msclkid=81e2f24a32cc185d275d953d60760226&couponCode=NEWYEARCAREERJP
・『シリコンバレー一流プログラマーが教える Goプロフェッショナル大全』酒井 潤 (著)
https://www.amazon.co.jp/%E3%82%B7%E3%83%AA%E3%82%B3%E3%83%B3%E3%83%90%E3%83%AC%E3%83%BC%E4%B8%80%E6%B5%81%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%83%BC%E3%81%8C%E6%95%99%E3%81%88%E3%82%8B-Go%E3%83%97%E3%83%AD%E3%83%95%E3%82%A7%E3%83%83%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E5%A4%A7%E5%85%A8-%E9%85%92%E4%BA%95-%E6%BD%A4/dp/4046070897