pointer

Go言語 ポインター

Go言語には、ポインタがあります。 ポインタとは、メモリのアドレスのことです。アドレスは`0xc0000b4008`のような16進数で表されます。

ポインタ

Go 言語には、ポインタがあります。 ポインタとは、メモリのアドレスのことです。アドレスは 0xc0000b4008 のような 16 進数で表されます。

ポインタを正確に理解するためには、先に変数とメモリの関係を知っておく必要があるでしょう。この記事では詳しく触れませんが、以下の記事が参考になります。

変数とメモリの関係 - 苦しんで覚えるC言語

Go 言語のポインタの構文は、主に &(アンパサンド)と *(アスタリスク)を使用します。

& アドレス演算子

1 個の & によって表現される「アドレス演算子」は、変数のメモリ内アドレスを決定するものです。変数の値はコンピュータの RAM(ランダムアクセスメモリ)とは、に保存(ストア)されます。値がストアされる場所を、その変数の「メモリアドレス」と呼びます。以下のように、メモリアドレスを 16 進数で表示します。

age := 24
fmt.Println(&age) // 0xc000136008

このように、アドレス演算子 & はその値のメモリアドレスを提供します。

デリファレンス

アドレス演算子の逆を行う演算が「デリファレンス」(逆参照、間接参照)です。メモリアドレスで参照される値を求めます。デリファレンスを行うために、* を使用しています。

age := 24
address := &age
 
fmt.Println(*address) // 24

なお C 言語と異なり、メモリアドレスをポインタ演算によって操作できません、Go 言語は安全でない演算を許可しないためです。

age := 24
address := &age
 
address++ // invalid operation: address++ (non-numeric type *int)

ポインタの型

前述の例のように、アドレス演算子で取得したメモリアドレスはポインタ型となります。 例えば、address 変数は *int という型を持っていることがわかります。

age := 24
address := &age
 
fmt.Printf("addressの型は %T です。\n", address)
// addressの型は *int です。

このポインタ型は、変数宣言・関数パラメータ・戻り地の型・構造体のフィールド型など型が使える場所ならあらゆる場所で使用できます。

var name *string
 
joe := "Joe"
 
name = &joe
 
fmt.Println(name) // 0xc00008e1e0
fmt.Println(*name) // Joe

構造体へのポインタ

ポインタは、しばしば構造体に対して使われます。そのため、構造体へのポインタを快適に使う工夫をいくつか提供しています。

文字列や数と違って、複合リテラルにはアドレス演算子を前置できます。

type person struct {
	name string
	age  int
}
 
joe := &person{
	name: "Joe",
	age:  24,
}
fmt.Println(joe) // &{Joe 24}

また構造体のフィールドにアクセスするためにわざわざその構造体をデリファレンスする必要がありません。

// 以下の2つは同じ
fmt.Println(joe.name) // Joe
fmt.Println((*joe).name) // Joe

配列へのポインタ

配列へのポインタも構造体と同様です。

array := &[3]int{1, 2, 3}
 
fmt.Println(array[1]) // 2
fmt.Println((*array)[1]) // 2

隠れたポインタ

ポインタを使用する際に、常に明示的に指定しているわけはありません。 例えば、マップやスライスは宣言していなくても舞台裏でポインタが使用されています。


Contributors

> GitHub で修正を提案する
この記事をシェアする
はてなブックマークに追加

関連記事