ポインタ

ポインタは、変数の値が格納されているメモリのアドレスを指すものです。

ポインタの使い方

基本的な操作は次の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)
}

ポインタのメリット

メソッドのレシーバをポインタにした際のメリットや出来ることを確認しましょう。