Goのポインタとは
ある変数のアドレス(メモリの番地)を示すもの。(=その変数の値がどこに格納されているかを示すもの。)
ポインタを操作する二つの演算子(&と*)
アドレス演算子(&)
変数名に前置することで、その値が格納されているメモリ内アドレスを取得できる。
num := 5
fmt.Println(&num) // 0xc0000100a0
デリファレンス演算子(*)
メモリアドレスで参照される値を取得できる。(=メモリアドレスに格納されている値を取得できる。)
num := 5
address := &num
fmt.Println(address) // 0xc000100010 参照先見る
fmt.Println(*address) // 5 デリファレンスしてメモリに格納されている値を見る
後述のポインタ型をデリファレンスすることで値の書き換えもできる。
var lang *string
mainLang := "Go"
lang = &mainLang
fmt.Println(*lang) // Go
*lang = "C#" // デリファレンスしてメモリ先の値を変更
fmt.Println(*lang) // C#
ポインタ型
ポインタ型は、型名に*を前置して宣言することができる。
ポインタ型の変数には、指定した型の変数のへのポインタを表現できる。
※型の前に * が置かれればポインタ型であり、変数名の前に置かれればデリファレンス演算子である。
var text *string // *string型の変数text
text := "test text"
address := &text
fmt.Println(*address) // デリファレンス演算子
自動的なデリファレンス
構造体や配列では、複合リテラルにアドレス演算子&を前置できる。
その値を利用する際はデリファレンス演算子*なしで、自動でデリファレンスされる。
下記のように構造体のフィールドを参照する際も、構造体自体を参照する際も、デリファレンスを明示的に行っていない。
※感覚としてはC#等の参照型のように使うことができる。
値を格納している場所を指すポインタ型と参照型は似ている。
type person struct {
name, superpower string
age int
}
timmy := &person{
name: "Timothy",
age: 10,
}
timmy.superpower = "flying"
fmt.Printf("%+v\n", timmy) // &{name:Timothy superpower:flying age:10}