ポインタは、その中にメモリアドレスを格納する便利なものです。
構造体は、Goにおける一まとまりのデータ構造を作成するデータ型です。
この記事では、Golangにおける構造体のポインタについて解説します。
Golang 構造体のポインタの構文
構造体へのポインタの構文は、他のデータ型のポインタと同じように記述します。
package main
import "fmt"
func main() {
// 構造体を定義
type Person struct {
Name string
Age int
}
// ポインタ変数を定義
var personPointer *Person
tanaka := Person{
Name: "Tanaka",
Age: 20,
}
// ポインタを割り当てる
personPointer = &tanaka
fmt.Println(personPointer)
}
ポインタ変数を用いたStructのフィールドへのアクセス
ポインタを使ったフィールドへのアクセスは実に簡単で、構造体そのものからアクセスするのと同じです。
package main
import "fmt"
func main() {
// 構造体を定義
type Person struct {
Name string
Age int
}
// ポインタ変数を定義
var personPointer *Person
tanaka := Person{
Name: "Tanaka",
Age: 20,
}
// ポインタを割り当てる
personPointer = &tanaka
fmt.Println(personPointer.Name) // Tanaka
}
引数としての受け渡しとデータの変異性
操作するデータのサイズがかなり大きい場合は、関数のパラメータにポインタを使用します。これは、さまざまなプログラミング言語で一般的に行われている方法であり、Golangでも同じことができます。
関数内で構造体へのポインタを渡し、そのポインタを介して関数で構造体を操作すれば良いです。以下がその方法です。
package main
import "fmt"
// 構造体を定義
type Person struct {
Name string
Age int
}
func changeName(p *Person) {
p.Name = "Sato"
}
func main() {
var personPointer *Person
tanaka := Person{
Name: "Tanaka",
Age: 20,
}
personPointer = &tanaka
fmt.Println(personPointer.Name) // Tanaka
changeName(personPointer)
fmt.Println(personPointer.Name) // Sato
}
上記のコードを見てわかるように、changeName関数は構造体の元の値も変異させます。
これは、ポインタを引数として使用する際の非常に重要な特性です。
何が起きているかというと、関数内の構造体がローカルに変更されるのではなく、ポインタが元の値で変更しているのです。コピーではなくオリジナルを変更したい時に非常に便利ですね。ちなみにこれを「参照渡し」と言います。