まくまくHugo/Goノート
ポインタを扱う
2017-09-04
Go 言語には、C/C++ と同様にポインタが存在します。構文もかなり似ていますが、簡潔に記述できるような工夫がされています。

Go 言語のポインタの基本

Go 言語では、変数の型のプレフィックスとしてアスタリスク (*) を付けると、ポインタ型の変数になります。 ポインタ変数は、その型の値が格納されているメモリアドレスを保持します。 ポインタ変数のゼロ値(初期値)は nil です。

var p *int             // p is a pointer to int
fmt.Printf("%v\n", p)  // <nil>

既存の変数のアドレスは & プレフィックスをつけて取得できるので、次のようにしてポインタ変数に格納することができます。

i := 100
p = &i

ポインタ経由で、格納されている値にアクセスするには、ポインタ変数のプレフィックスとして * を付けます。 下記の例では、ポインタ経由で参照先の値を書き換えています。

var i int = 100
var p *int = &i
fmt.Println(i)   //=> 100
fmt.Println(*p)  //=> 100

*p = 200         // ポインタ経由で値を書き換える
fmt.Println(i)   //=> 200
fmt.Println(*p)  //=> 200

このあたりのポインタの文法は、C/C++ 言語とほとんど同じですね。 ただし、Go 言語ではポインタ演算(アドレスの足し算など)を行うことはできません。 そういったアクセスを禁止することで、不正なメモリアドレスへアクセスしてしまう危険性を排除しています。

関数内から呼び出し元の変数の値を書き換える

Go 言語の関数のパラメーターは、通常は C/C++ 言語と同様に値渡し(値のコピーが渡される)となるため、下記のような関数を実行しても、呼び出し側の数値を変更することはできません。

func add100(n int) {
	n += 100  // 呼び出し側の値は変更されない
}

ポインタ型のパラメーターを受け取るように変更すると、呼び出し元の変数が格納されているメモリアドレスを受け取ることができます。 そのメモリアドレスに格納されている値を、関数内から直接書き換えることができるようになるため、結果的に呼び出し側でパラメーターとして渡した変数の値を書き換えることができます。 下記のサンプルでは、int のポインタを受け取り、呼び出し側の int 変数の値を変更しています。

func add100(n *int) {
	*n += 100  // 呼び出し側の値を変更できる
}

func main() {
	n := 50
	add100(&n)
	println(n)  //=> 150
}
2017-09-04