Go言語のポインタと配列
2026/07/28
ポインタ型
ポインタ型*Tは型Tの値を指す参照です。
x := 42
p := &x
*p = 100
fmt.Println(x) // 100値渡しとポインタ
- ポインタ演算(
p + 1など)はできません - ポインタのゼロ値は
nilで、nilの間接参照はパニックです - 関数の引数は値渡しです。呼び出し元を変更したいときだけポインタを渡します
var p *int // ゼロ値はnil
fmt.Println(*p) // panic: nilポインタの間接参照関数にintを渡すと、その時点の値のコピーが引数に入ります。関数内で引数を書き換えても、呼び出し元の変数は変わりません。呼び出し元を書き換えたいときは&vでアドレスを渡し、関数内で*nを使います。
func setToZero(n int) { n = 0 } // 引数nだけが0になる
func setToZeroPtr(n *int) { *n = 0 } // *n経由で呼び出し元を0にする
count := 5
setToZero(count)
fmt.Println(count) // 5
setToZeroPtr(&count)
fmt.Println(count) // 0すべてをポインタにする必要はありません。小さな値型はコピーのまま渡すことが多いです。Goは常に値渡しです。ポインタを渡しても渡るのはポインタ値のコピーで、指す先は共有されます。
newによる割り当て
new(T)は型Tのゼロ値を置いた領域を確保し、そのアドレス*Tを返します。*intや*Userのように、ゼロ値へのポインタが欲しいときに使います。var n intと&nで同じポインタを得られますが、newなら中間変数を別に用意せず、1つの式で*Tを得られます。次の2つは同じ意味です。
p := new(int)
*p = 42
var n int
q := &n
*q = 42スライス・マップ・チャネルは内部の初期化が必要なため、newでは使える状態になりません。これらはmakeで作ります。
配列型
配列[n]Tは長さnが型の一部です。[3]intと[4]intは別の型で、相互代入できません。配列とスライスを同じだと考えがちですが、配列の長さは型に固定され、スライス[]Tは長さ可変のビューです。
配列は値型
配列を代入・引数渡しすると、要素全体がコピーされます。スライスも値渡しですが、コピーされるのはヘッダ(元配列への参照・len・cap)だけで、要素が並ぶ元配列は共有されます。大きな配列をそのまま渡すと要素まで丸ごとコピーされるため、可変長の処理にはスライス[]Tを使うことが多いです。
arr := [3]int{1, 2, 3}
dup := arr // 配列全体のコピー
dup[0] = 0
fmt.Println(arr[0], dup[0]) // 1, 0