はじめに
Goのポインタでつまったところがあったので、整理も兼ねて記事にします
具体的には、デリファレンス
という動きについて、つまずいたので、もし聞いたことがない方には参考になると思います。
Goのポインタについて
整理のため、Goのポインタについてまとめます
宣言と使用方法
// 変数
var str string
str = "test"
fmt.Println(str) // test
// ポインタ型の変数
var strp *string
// 変数のポインタを格納
// &をつけると変数のアドレスが取得できるのでそれをポインタ型の変数に格納する
strp = &str
// ポインタ型の変数を普通に出力するとアドレスが出力される
fmt.Println(strp) // 0xc000012090のような形式
// ポインタ型の変数に*をつけると中身が取得できる
// これをデリファレンスという
value := *strp
fmt.Println(value) // test
値の書き換え
var str string
str = "test"
var strp *string
strp = &str
// 値を書き換える場合もデリファレンスを使い、中身にアクセスする
*strp = "new"
fmt.Println(*strp) // new
// strpは、strのアドレスを代入したため、strpはstrと同じアドレスとなっている
// アドレスが同じなので、strpを書き換えるとstrも変わる
fmt.Println(str) // new
ポインタ型宣言時はnilになる
つまったポイント1つ目です。
*strp = "new"
で、値を代入できるのかと知り、以下のコードを実行するとエラーになりました。
var strp *string
*strp = "new"
fmt.Println(*strp)
理由は、var strp *string
を宣言時は、ポインタ型変数はnilになります。
したがって、*strpでアクセスしようとすると、invalid memory address or nil pointer dereference
というエラーになります
以下のようにすると、エラーは解消します
var strp *string
// newでメモリを確保する
strp = new(string)
*strp = "new"
fmt.Println(*strp)
構造体では自動でデリファレンスされる
つまったポイント2つ目です。
type Person struct {
Name string
Age int
}
var person Person
person = Person{
Name: "aaa",
Age: 12,
}
var personp *Person
personp = &Person{
Name: "aaa",
Age: 12,
}
上記のように構造体でポインタを試そうとしました。
*変数名で、中身を取得できるので、*personp.Nameのような形で出力しようとするとエラーとなりました。
理由は、構造体の場合は自動でデリファレンスされるので、*personp.Nameにしなくてもよいみたいです。(invalid operation: cannot indirect personp.Name (variable of type stringというエラーが出てしまいます)
type Person struct {
Name string
Age int
}
var person Person
person = Person{
Name: "aaa",
Age: 12,
}
var personp *Person
personp = &Person{
Name: "aaa",
Age: 12,
}
fmt.Println(person.Name) // aaa
// 自動デリファレンスされるので*は不要
// fmt.Println(*personp.Name)
fmt.Println(personp.Name) // aaa