Go のポインタは C のポインタに似ている。変数のアドレスを得るためには &
を使い、ポインタのさす値を参照するには *
を使う。宣言するのに *
を使うのも一緒だけど、Go の場合には変数名ではなく型の前につける。
package main import "fmt" func main() { var n int = 10 var p *int = &n fmt.Println(n) fmt.Println(*p) *p = 100 fmt.Println(n) fmt.Println(*p) fmt.Println(p) fmt.Println(p == &n) }
^o^ > go run pointer.go 10 10 100 100 0xc042008210 true
C と違う点はほかにもある。Go のポインタは、整数値の代入や加減算はできないようになっている。配列のアドレスもそうだ。C では配列へのポインタはその配列の先頭要素へのポインタになっていて、各要素にアクセスするにはポインタをインクリメントしたりとかする。Go ではこういうことはできない。配列へのポインタは配列そのものへのポインタであって、配列の要素へのアクセスはできないようだ。もちろん、配列の要素へのポインタは作れる。
package main import "fmt" func main() { var a [4]int = [4]int{ 1,2,3,4 } var b [4]int = [4]int{ 10,20,30,40 } var p *[4]int = &a p0, p1 := &a[0], &a[1] fmt.Println(p) fmt.Println(*p) fmt.Println(a[0]) // fmt.Println(*p[0]) // error fmt.Println(p0) fmt.Println(*p0) fmt.Println(p1) fmt.Println(*p1) fmt.Println(a[1]) *p0 = 10 *p1 = 20 fmt.Println(a) p = &b fmt.Println(*p) }
^o^ > go run pointer_array.go &[1 2 3 4] [1 2 3 4] 1 0xc042002700 1 0xc042002708 2 2 [10 20 3 4] [10 20 30 40]
以前に、関数の呼び出しは値渡しだと書いた。関数のポインタを渡してやると、ポインタは仮引数にコピーされるけど、そのさしている値は呼び出し元と同じ値だ。つまり、ポインタを使えば参照渡しと同等のことかできる。
package main import "fmt" func swap(x *int, y *int) { tmp := *x *x = *y *y = tmp } func timesArray(n int, ary *[4]int) { for i := 0; i < len(*ary); i++ { ary[i] *= n } } func main() { var a int = 10 var b int = 20 var c [4]int = [4]int{ 1,2,3,4 } fmt.Println(a) fmt.Println(b) fmt.Println(c) swap(&a, &b) timesArray(10, &c) fmt.Println(a) fmt.Println(b) fmt.Println(c) }
^o^ > go run pointer_call.go 10 20 [1 2 3 4] 20 10 [10 20 30 40]
さて、ポインタの基本はこんなところ。