Golangのメソッドとは
メソッドとは、関数と同じようなものです。ただ、関数と違うのはレシーバを持つという点です。
メソッドの構文は以下のようになります。
func (レシーバー レシーバーの型)メソッド名(引数 引数の型) 戻り値 {
// 処理
}
メソッドを実行する際は、次のように記述します。
レシーバー.メソッド名
上記のような構文により、Golangではオブジェクト指向のようなメソッド呼び出しができます。
Golangにおけるメソッドの利点とは
メソッドには、通常の関数と比較していくつかの利点があります。
同じパッケージの中で同じ名前の関数は許されませんが、メソッドにはそれが当てはまらず、レシーバーが異なっていれば、同じ名前のメソッドを複数持つことができます。
もし2つの構造体があり、それらが同じメソッドを呼び出すとしても、Golangではそれが可能です。これは、メソッドの最も重要な側面の1つで、Golangをオブジェクト指向言語のように扱うことができます。
ところで、レシーバーとは?
レシーバーとは、関数を直接呼び出すことができる型のことです。
以下は、構造体型がメソッドを持つ例です。ここでは、構造体Bird がレシーバーになります。
package main
import (
"fmt"
)
type Bird struct{
name string
}
// メソッド定義
func (bird Bird)Fly() {
fmt.Println(bird.name, "は飛びます")
}
func main() {
bird := Bird{"Piyo"}
// メソッド呼び出し
bird.Fly() // Piyo は飛びます
}
上記のコードを見れば分かる通り、Bird型のオブジェクトであれば、Fly関数を呼び出すことができます。
ちなみに、レシーバの宣言はメソッドと同じパッケージ内にある必要があり、そうでない場合は動作しません。
レシーバーを使用する理由とは
レシーバを使うと、オブジェクト指向のやり方で関数呼び出しを記述することができます。
つまり、ある型のオブジェクトが作成されると、その型は自分自身から関数を呼び出すことができるのです。
package main
import (
"fmt"
)
type Person struct{
name string
}
// メソッド定義
func (person Person)Name(){
fmt.Println(person.name)
}
func main() {
// Person型のオブジェクトを作成
person := Person{"田中"}
// メソッド呼び出し
person.Name() // 田中
}
レシーバーの型
Golangで利用できるレシーバーは2種類あります。
値型のレシーバーとポインター型のレシーバーです。以下は、その両方を示すコード例です。
package main
import (
"fmt"
)
type Animal struct{
name string
}
func (a Animal)Run(){
fmt.Println(a.name, "は走る")
}
func (a *Animal)RunFaster(){
fmt.Println(a.name, "は走る")
}
func main() {
dog := Animal{"犬"}
dog.Run() // 犬 は走る
dog.RunFaster() // 犬 は走る
}
このように、宣言が異なっていても、どちらの関数も同じことを行っています。
構造体のメソッド
構造体はGolangの中で最もクラスに近い存在です。また、構造体によってメソッドを定義することができます。
構造体はデータのカプセル化を可能にし、メソッドを記述することで、オブジェクト指向言語におけるクラスのように振る舞うことができます。
以下は、構造体のメソッドを示す例です。
package main
import (
"fmt"
)
type Human struct{
name string
age int
}
func (h Human)Describe() {
fmt.Println(h.name, "は", h.age, "歳です")
}
func main() {
human := Human{"田中", 25}
human.Describe() // 田中 は 25 歳です
}