Go のポインター

Go のポインターの説明

ポインター

ポインターは変数が格納されているメモリーアドレスを保持する。C 言語と同様に、オブジェクトのアドレスを取得するには & を使い、ポインターが参照する値へアクセスするには * を使う。

package main

import "fmt"

func main() {
	var a1 int  // int 型の変数 a1 を定義する
	var p1 *int // int 型へのポインター変数 p1 を定義する

	p1 = &a1  // p1 に a1 のアドレスを格納する
	*p1 = 123 // 参照先、つまり a1 に 123 を代入する

	fmt.Println(a1)
	fmt.Println(p1)
	fmt.Println(*p1)
}

実行結果:

123
0xc00001c030
123

変数の値を渡すことを値渡しと呼ぶ。変数へのポインターを渡すと、関数から参照先の変数へアクセスできる。値渡しでは値のコピーだけが渡されるため、元の変数を変更できない。ポインターを渡すと、関数から変数を変更できる。

package main

import "fmt"

func main() {
	var a1 int = 123
	var a2 int = 123
	fn(a1, &a2)         // a1 は値を渡し、a2 はアドレスを渡す
	fmt.Println(a1, a2)
}

func fn(b1 int, b2 *int) {
	b1 = 456
	*b2 = 456
}

実行結果:

123 456

. 演算子を使うと、構造体の値と構造体へのポインターのどちらからでもフィールドへアクセスできる。

package main

import "fmt"

type Person struct {
	name string
	age  int
}

func main() {
	a1 := Person{"devkuma", 23} // Person の値を作成して初期化する
	p1 := &a1                   // a1 へのポインターを p1 に格納する
	fmt.Println(a1.name)        // 値からフィールドへアクセスする
	fmt.Println((*p1).name)     // ポインターをデリファレンスしてフィールドへアクセスする
	fmt.Println(p1.name)        // Go ではこの短い形式も使用できる
}

実行結果:

devkuma
devkuma
devkuma

領域の確保(new)

new() を使うと領域を動的に確保し、その領域へのポインターを取得できる。確保した領域は参照されなくなると、Go のガベージコレクターによって自動的に解放される。

package main

import "fmt"

type Book struct {
	title string
}

func main() {
	bookList := []*Book{}

	for i := 0; i < 10; i++ {
		book := new(Book)
		book.title = fmt.Sprintf("Title#%d", i)
		bookList = append(bookList, book)
	}
	for _, book := range bookList {
		fmt.Println(book.title)
	}
}

実行結果:

Title#0
Title#1
Title#2
Title#3
Title#4
Title#5
Title#6
Title#7
Title#8
Title#9