
Go言語の構造体で、ポインタの扱いで注意するところはありますか?
Go言語の構造体を学んでいく上で、構造体におけるポインタを押さえておく必要があります。
基本型のポインタと若干の違いもあります。
ですから、事前知識として基本型のポインタについての理解が必要です。
ポインタの知識が曖昧な方は、当ブログ記事を参考にしてください。
Go言語の構造体でポインタを定義する2種類の方法
Go言語で構造体でポインタを定義する方法は2種類あります。
それぞれの定義方法を確認していきましょう。
new()関数を使ってポインタ定義する
new()
関数で構造体のポインタを定義する記述方法は下記の通りです。
では、プログラムで確認していきましょう。

今回の構造体はロールプレイングゲームのキャラクターにしてみました!
// new()関数を使ってポインタ定義
package main
import "fmt"
// 構造体を定義
type Character struct {
Name string
Attribute string
Hp int
Mp int
Money int
}
func main() {
// new()を使用する
player1 := new(Character)
fmt.Println(player1)
// 実体を出力する
fmt.Println(*player1)
}
// 出力結果
$ go run main.go
&{ 0 0 0}
{ 0 0 0}
&{ 0 0 0}
の &
がポインタを表しています。
そして、初期化していないので各フィールドには型の初期値が代入されています。
& を使ってポインタ定義する
&
を使ったポインタ定義の記述方法は下記の通りです。
では、プログラムで確認しましょう。
// new()関数を使ってポインタ定義
package main
import "fmt"
// 構造体を定義
type Character struct {
Name string
Attribute string
Hp int
Mp int
Money int
}
func main() {
// new()を使用する
player1 := new(Character)
fmt.Println(player1)
// 実体を出力する
fmt.Println(*player1)
// &を使用してポインタ定義
player2 := &Character{}
fmt.Println(player2)
// 実体を出力する
fmt.Println(*player2)
}
// 出力結果
$ go run main.go
&{ 0 0 0} // new()を使った出力
{ 0 0 0}
&{ 0 0 0} // &を使った出力
{ 0 0 0}
どちらも同じ出力結果になっているのを確認できます。

じゃーどっちを使うのがいいの?
構造体のポインタ定義は &
を使う方が一般的で &
の方がポインタをイメージしやすいからという見解が多いようです。
構造体を関数で使用してみる
ここで重要なポイントとして、構造体は値渡しの型です。
ここを踏まえた上で、ポインタの基本を学習と同じように2つの関数でプログラムの動きを確認していきましょう。
関数の引数にポインタを使用しない場合
関数の引数にポインタを使用しない場合のプログラムを確認していきます。
その前に、構造体を初期化していきます。
// new()関数を使ってポインタ定義
package main
import "fmt"
// 構造体を定義
type Character struct {
Name string
Attribute string
Hp int
Mp int
Money int
}
func main() {
// 構造体を初期化
player3 := Character{
Name: "もりぴ",
Attribute: "勇者",
Hp: 100,
Mp: 50,
Money: 1000,
}
fmt.Println(player3)
}
// 出力結果
$ go run main.go
{もりぴ 勇者 100 50 1000}

構造体定義の復習も兼ねて、初期化終了いたしました!
では、本題の関数の引数にポインタを使用しない(値渡し)プログラムを確認していきましょう。
// new()関数を使ってポインタ定義
package main
import "fmt"
// 構造体を定義
type Character struct {
Name string
Attribute string
Hp int
Mp int
Money int
}
// 関数を定義(値渡し)
func upscore(player Character) {
fmt.Println(player.Name, "の各ステータスがアップしました!")
player.Hp += 100
player.Mp += 50
player.Money += 500
}
func main() {
// 構造体を初期化
player3 := Character{
Name: "もりぴ",
Attribute: "勇者",
Hp: 100,
Mp: 50,
Money: 1000,
}
fmt.Println(player3)
// 値渡しの関数を実行
upscore(player3)
fmt.Println(player3)
}
// 出力結果
$ go run main.go
{もりぴ 勇者 100 50 1000}
もりぴ の各ステータスがアップしました!
{もりぴ 勇者 100 50 1000}

あれ?値が変わっていませんね…
構造体が値渡しなので、player3
のデータをコピーして関数の引数として渡しています。
コピーされたデータなので元のデータには影響しません。
関数の引数にポインタを使用した場合
それでは、関数の引数にデータのアドレスを渡す(参照渡し)ためにポインタを使用してみましょう。
// new()関数を使ってポインタ定義
package main
import "fmt"
// 構造体を定義
type Character struct {
Name string
Attribute string
Hp int
Mp int
Money int
}
// 関数を定義(参照渡し)
func upscore2(player *Character) {
fmt.Println(player.Name, "の各ステータスがアップしました!")
player.Hp += 100
player.Mp += 50
player.Money += 500
}
func main() {
// 構造体を初期化
player3 := Character{
Name: "もりぴ",
Attribute: "勇者",
Hp: 100,
Mp: 50,
Money: 1000,
}
fmt.Println(player3)
// 参照渡しの関数を実行
upscore2(&player3)
fmt.Println(player3)
}
// 出力結果
$ go run main.go
{もりぴ 勇者 100 50 1000}
もりぴ の各ステータスがアップしました!
{もりぴ 勇者 200 100 1500}

無事に私のHP・MP・Moneyの各ステータスがアップしました!

あれ?!関数を定義している変数名の前に * を付けなくてもいいんですか?

いいところに気付きましたね!構造体では省略してもOKです。
基本型での参照渡しで実体にアクセスするには、* が必要でしたが構造体では不要です。
// 関数を定義(参照渡し)
// 基本型の場合は実体にアクセスすのに*が必要
func upscore2(player *Character) {
fmt.Println(player.Name, "の各ステータスがアップしました!")
// (* ) は構造体の参照渡しでは省略可
(*player).Hp += 100
(*player).Mp += 50
(*player).Money += 500
}
上記のようにプログラムを記述してもエラーにならずに、同じ出力結果が得られます。
【まとめ】Go言語の構造体でポインタを使用するには?
今回は構造体を関数の引数として使用する場合に必要な、ポインタの定義についてお伝えしていきました。
それでは、今回のまとめにはいります。
以上です。
基本型のポインタの基本を押さえていれば、それほど難しくはなかったのではないでしょうか。
難しく感じた型は、Go言語入門編を振り返ってみましょう。
comment