
Go言語にメソッドという機能がるらしいんですが、関数と何が違うの?
今回はGo言語のメソッドについてお伝えします。
他のプログラミング言語を学習してきた方にはお馴染みのメソッドですが、Go言語では定義方法に違いがあります。
この記事では、他のプログラミン言語を習得していない方でも理解できるように進めていきます。
ただし、Go言語の関数とポインタの基本を押さえておく必要があります。
当ブログの記事を参考にしてみてください。


Go言語のメソッドとは?
Go言語では、他のプログラミング言語で使用される class
が無いため、レシーバーで所定の型(今回は構造体の型)と紐づけします。
// 構造体と型を紐付ける
package main
import "fmt"
// 構造体を定義
type 型名 struct{
フィールド名1 型
フィールド名2 型
・
・
・
フィールド名x 型
}
// メソッドを定義
// (変数名 構造体の型)がレシーバー
func (変数名 構造体の型) メソッド名() {
// 処理内容
}
func main() {
}
構造体の型と関数を紐付けるレシーバーは、下記のように記述します。
Go言語のメソッドを定義する
では、実際にGo言語のメソッドをプログラムで定義し、実際に動きを確認してみましょう。
値レシーバーでメソッドを定義する
値レシーバーは、構造体のデータをコピーして渡して処理するものです。
ですから、コピー元のデータには影響を受けません。
今回は、値レシーバーの例として構造体のデータを呼び出す処理をしてみましょう。
// 値レシーバーでメソッドを定義する
package main
import "fmt"
// 構造体を定義
type Character struct {
Name string
Attribute string
Level int
Hp int
Mp int
Money int
}
// メソッドを定義
func (a Character) LevelUpMsg() {
fmt.Println(a.Name, "、はレベルアップした!")
}
func main() {
// 構造体を初期化
player1 := Character{
Name: "morip",
Attribute: "勇者",
Level: 1,
Hp: 100,
Mp: 50,
Money: 300,
}
// メソッドを呼び出し
player1.LevelUpMsg()
}
// 出力結果
$ go run main.go
morip は、レベルアップした!
メソッドの呼び出しは以下のように記述します。
普通に関数を使用すると、その関数がどこにあるかを知っておく必要があります。
メソッドだとコードを見るだけで、どの関数が呼び出されて実行されているのか把握しやすくなります。
ポインタレシーバーでメソッドを定義する
ポインタレシーバーは、構造体のデータのアドレスを渡して処理します。
ですから、コピー元のデータを直接書き換えることができます。
ポインタレシーバーは下記のように記述します。
それでは、ポインタレシーバーのプログラムを確認してみましょう。

今回はロールプレイングゲームのレベルアップの処理をしてみましょう!
// ポインタレシーバーでメソッドを定義する
package main
import "fmt"
// 構造体を定義
type Character struct {
Name string
Attribute string
Level int
Hp int
Mp int
Money int
}
// メソッドを定義
// ポインタレシーバーなので * を付ける
func (a *Character) LevelUpCal() {
fmt.Println(a.Name, "は、レベルアップした!")
a.Level++
a.Hp += 100
a.Mp += 50
a.Money += 500
fmt.Println(a.Name, "は、レベルが", a.Level, "HPが", a.Hp, "MPが", a.Mp, "所持金が", a.Money, "にアップした。")
}
func main() {
player1 := Character{
Name: "morip",
Attribute: "勇者",
Level: 1,
Hp: 100,
Mp: 50,
Money: 300,
}
// 初期化の値を確認
fmt.Println(player1)
// メソッドを呼び出し
player1.LevelUpCal()
}
// 出力結果
$ go run main.go
{morip 勇者 1 100 50 300}
morip は、レベルアップした!
morip は、レベルが 2 HPが 200 MPが 100 所持金が 800 にアップした。
player1
の初期化した時の値とメソッドを実行した時のデータが書き換わっているのが確認できます。

次に、メソッドに引数を与えてみましょう。
プレイヤーが職業を変更した時のプログラムを例にします。
// ポインタレシーバーでメソッドを定義する
package main
import "fmt"
// 構造体を定義
type Character struct {
Name string
Attribute string
Level int
Hp int
Mp int
Money int
}
// メソッドを定義(引数を渡す)
func (b *Character) JobChange(att string) {
b.Attribute = att
fmt.Println(b.Name, "は", b.Attribute, "に転職した。")
}
func main() {
player1 := Character{
Name: "morip",
Attribute: "勇者",
Level: 1,
Hp: 100,
Mp: 50,
Money: 300,
}
// 初期化の値を確認
fmt.Println(player1)
// メソッドに引数を渡す
player1.JobChange("戦士")
}
// 出力結果
$ go run main.go
{morip 勇者 1 100 50 300}
morip は 戦士 に転職した。

moripが”勇者”から”戦士”に転職できました!
メソッドはポインタレシーバーで定義するのが一般的

あれ?!アドレスを渡すのに & を付けなくてもいいんですか!

めちゃくちゃいいところに気が付きましたね!
メソッドは値レシーバーやポインタレシーバーをメソッド側で管理するので、メソッドを呼び出す側は値レシーバーやポイントレシーバーを意識することなく呼び出すことができます。
構造体のデータを変更されたくない場合を除いて、メソッドはポインタレシーバーで定義するのが一般的です。
【まとめ】Go言語の構造体とメソッド
今回は、Go言語の構造体とメソッドについてお伝えしてきました。
それでは、まとめにはいります。
以上です。
関数とポインタの基本を押さえていないと、ちょっと難しかったかもしれません。
ですが、メソッドを理解することでワンランク上のプログラミングを身につけることができるでしょう。
難しかった方は、もう一度、関数とポインタの基本を復習してみましょう。
comment