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