メソッドと構造体の関係を理解する!Go言語の定義方法

Go言語
この記事は約8分で読めます。
Go初学者
Go初学者

Go言語にメソッドという機能がるらしいんですが、関数と何が違うの?

この記事ではGo言語のメソッドについて理解できます!
  • メソッドとは?
  • メソッドを定義してみる
  • 値レシーバーとポインタレシーバーをプログラムで確認

今回はGo言語のメソッドについてお伝えします。

他のプログラミング言語を学習してきた方にはお馴染みのメソッドですが、Go言語では定義方法に違いがあります。

この記事では、他のプログラミン言語を習得していない方でも理解できるように進めていきます。

ただし、Go言語の関数とポインタの基本を押さえておく必要があります。

当ブログの記事を参考にしてみてください。

もりぴ
この記事を書いた人

XHTML1.0時代にHTML&CSSを勉強した経験あり。無趣味だった私が2020年5月からプログラミング学習を開始し現在も挫折せずに趣味で学習を楽しんでいる51歳。プログラミングの楽しさをブログを通してお伝えしていきます。

もりぴをフォローする

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 は、レベルアップした!
このプログラムのポイント!
  • (a Character) でレシーバーを定義
  • LevelUpMsg() でメソッドを定義
  • player1.LevelUpMsg() でメソッドを呼び出し

メソッドの呼び出しは以下のように記述します。

変数名.メソッド名()

普通に関数を使用すると、その関数がどこにあるかを知っておく必要があります。

メソッドだとコードを見るだけで、どの関数が呼び出されて実行されているのか把握しやすくなります。

ポインタレシーバーでメソッドを定義する

ポインタレシーバーは、構造体のデータのアドレスを渡して処理します。

ですから、コピー元のデータを直接書き換えることができます。

ポインタレシーバーは下記のように記述します。

(変数名 *構造体の型)

それでは、ポインタレシーバーのプログラムを確認してみましょう。

もりぴ
もりぴ

今回はロールプレイングゲームのレベルアップの処理をしてみましょう!

// ポインタレシーバーでメソッドを定義する
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初学者

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

もりぴ
もりぴ

めちゃくちゃいいところに気が付きましたね!

POINT

メソッドは値レシーバーやポインタレシーバーをメソッド側で管理するので、メソッドを呼び出す側は値レシーバーやポイントレシーバーを意識することなく呼び出すことができます。

構造体のデータを変更されたくない場合を除いて、メソッドはポインタレシーバーで定義するのが一般的です。

【まとめ】Go言語の構造体とメソッド

今回は、Go言語の構造体とメソッドについてお伝えしてきました。

それでは、まとめにはいります。

この記事で押さえておくこと!
  • Go言語のメソッドは、所定の型と紐づけた関数のことを指す
  • 構造体の型と関数を紐付けるレシーバーは (変数名 構造体の型) で定義する
  • メソッドは 変数名.メソッド名() で呼び出す
  • 値レシーバーは、構造体のデータをコピーして渡して処理する
  • ポインタレシーバーは、構造体のデータのアドレスを渡して処理する
  • ポインタレシーバーは (変数名 *構造体の型) で定義する
  • メソッドはポインタレシーバーで定義するのが一般的

以上です。

関数とポインタの基本を押さえていないと、ちょっと難しかったかもしれません。

ですが、メソッドを理解することでワンランク上のプログラミングを身につけることができるでしょう。

難しかった方は、もう一度、関数とポインタの基本を復習してみましょう。

comment

タイトルとURLをコピーしました