【Go言語入門】9.メソッドについてさくっと学ぶ

これまで様々な開発を行ってきて基本的なことを振り返ることもなかったので、丁度いい機会ということで、初心に返ってGoにおいてのメソッドを一つずつ復習しました。

前回の記事

定義

SwiftやC++などのオブジェクト指向言語では、各オブジェクトが自身を操作する関数(メンバ関数)を持つことができるのですが、これをメソッドと呼んだりします。(というのが僕の認識です)

しかしながらGoは、C同様オブジェクト指向言語ではないのでクラスの概念がなく、オブジェクトが存在しません。なのでオブジェクト指向言語とはメソッドの意味が少し異なります。

A Tour of Goによるとレシーバ引数を伴う関数だそうです。

前回の記事のソースコードを例に挙げていきます。

レシーバ(receiver)

レシーバは構造体と関数を紐付けるためのもう一つの引数という覚え方で問題ないかと思います。

具体的な使い方としてはfunc (レシーバ引数 構造体) メソッド名 (引数) {}というように、funcキーワードとメソッド名の間にもう一つ引数をいれます。

以下をご覧ください。

package main

import "fmt"

type User struct {
  Id          int
  Name        string
  Description string
  Follow      int
  Follower    int
}

func follow(u1, u2 *User) {
  u1.Follow++
  u2.Follower++
}

func main() {
  ken := User{Name: "Ken"}
  mio := User{Name: "Mio"}
  follow(&ken, &mio)
  fmt.Println(ken, mio)
}

// >>> {0 Ken  1 0} {0 Mio  0 1}

前回の関数がしっかり作用するように直した最終的な結果です。

前回は単なる関数で書いておりましたが、メソッドにすると構造体の持ち物っぽい振る舞いが出来るようになります。

package main

import "fmt"

type User struct {
  Id            string
  Name          string
  Description   string
  FollowingIds  []string
  FolloweredIds []string
}

func (u1 *User) Follow(u2 *User) {
  u1.FollowingIds = append(u1.FollowingIds, u2.Id)
  u2.FolloweredIds = append(u2.FolloweredIds, u2.Id)
}

func main() {
  ken := User{Id: "ken_id", Name: "Ken"}
  mio := User{Id: "mio_id", Name: "Mio"}
  ken.Follow(&mio)
  fmt.Println(ken, mio)
}

// >>> {ken_id Ken  [mio_id] []} {mio_id Mio  [] [mio_id]}

前回と比べよりそれっぽく書いてみました。フィールド名などを多少変更しておりますが、先ほどとしていることは同じです。

ここで見るべき点は変数kenが関数Followにアクセスできている点です。

視覚的にもよりセマンティックになったような感じがしますね。

レシーバを使う際の注意点としては構造体と同一パッケージに定義しなければいけない、ということです。

また、ポインタを引数にするときと通常の型を引数にするときの振る舞いの違いは、前回の記事の構造体、前々回の記事のポインタにて解説しておりますので、まだ知らない方はぜひご覧ください。