ポインタ
ポインタは、変数の値が格納されているメモリのアドレスを指すものです。
ポインタの使い方
基本的な操作は次の3つです。
- ポインタの型は参照先の型の前に
*
を付ける(例:*int
) - ポインタを生成するには、変数名の前に
&
を付ける(例:&i
) - ポインタが指す変数を参照する(デリファレンスと呼ぶ)には、変数の前に
*
を付ける(例:*p
)
サンプルコードを次に示します。
var p *int
i := 12
// &はiのメモリアドレス(ポインタ)を示す
p = &i
// iのメモリアドレスを参照する
fmt.Println(p)
// *はポインタを経由してiの値を参照する
fmt.Println(*p)
// *でポインタを経由してiに値を設定する
*p = 21
// iが変更されている
fmt.Println(i)
// 実行結果:
// 0xc000010010 ←メモリアドレスは環境に依るため、この値になるとは限らない
// 12
// 21
new
関数で『ポインタ型の変数』と『ポインタの参照先のデータ領域』の両方を初期化できます。
p := new(int)
// 参照先のデータ領域がゼロ値で初期化されている
fmt.Println(*p)
// 参照先の値を更新
*p++
// 更新を確認
fmt.Println(*p)
// 実行結果:
// 0
// 1
配列と構造体のデリファレンス
配列と構造体のデリファレンスでは、*
を省略できます。
type Point struct {
X int
Y int
}
func main() {
n := [...]int{2, 3}
p1 := &n
// 演算子の優先順位を調整するため括弧で括る
fmt.Println((*p1)[0])
// (*p1)[0]と同等
fmt.Println(p1[0])
point := Point{X: 1, Y: 2}
p2 := &point
// 演算子の優先順位を調整するため括弧で括る
fmt.Println((*p2).X)
// (*p2)[0]と同等
fmt.Println(p2.X)
}
ポインタのメリット
メソッドのレシーバをポインタにした際のメリットや出来ることを確認しましょう。