Go言語_メソッド

メソッドについて

メソッドとは

Go言語におけるメソッドとは、特定の型(主に構造体)に関連付けられた関数です。

一般的なオブジェクト指向言語におけるクラスメソッドを作成することと同じような機能です。


ただし、Go言語にはクラスという概念がないので、若干異なります。

一般的なオブジェクト指向言語 メソッドはクラスと強く関連付けられていて、メソッドの定義もクラスの中で行います。
Go 言語 構造体の中に定義するのではなく、メソッドの引数の型で型と関連付けられます。

メソッドの定義

メソッドの定義は以下のように記載します。


func (仮引数 型) 名前(仮引数 型, ...) 返り値の型 { ... }

func と名前の間にある (仮引数 型) を「レシーバ」といいます。

メソッドはレシーバの型と関連付けられます。


メソッドの定義例

関数の定義とメソッドの定義方法は以下のような差異になります。

名前空間が異なるので、同名の関数とメソッドを記述できます。


package main

import "fmt"

type Calc struct{ num1, num2 int }

// 関数
func Add(q Calc) int {
	return q.num1 + q.num2
}

// メソッド
func (p Calc) Add() int {
	return p.num1 + p.num2
}

func main() {
	// 関数呼び出し
	q := Calc{2, 3}
	fmt.Println(Add(q))

	// メソッド呼び出し
	p := Calc{7, 4}
	fmt.Println(p.Add())
}

メソッドを使う利点

メソッドは型に紐づくので、型ごとに同名のメソッドを定義できます。

関数では「ExecXxxx」「ExecYyyy」のように、名前を分けて定義してしまいがちですが、メソッドならば「.Exec()」で異なる処理を行えます。

また、メソッドは型に紐づくので、コード上の影響範囲が分かりやすい点も挙げられます。


package main

import "fmt"

type NumData struct {
	num int
}

type StrData struct {
	str string
}

func (t NumData) Exec() {
	fmt.Println(t.num)
}

func (t StrData) Exec() {
	fmt.Println(t.str)
}

func main() {
	obj1 := NumData{7}
	obj2 := StrData{"method"}

	obj1.Exec() // 7
	obj2.Exec() // method
}

ポインタレシーバ

値レシーバ

値レシーバとは「値型」に対してメソッド定義されたものです。


ポインタレシーバ

「ポインタ型」に対してメソッド定義されたものが「ポインタレシーバ」です。


package main

import "fmt"

type StrData struct {
	str string
}

// ポインタレシーバ
func (t *StrData) ptrExec() {
	fmt.Println(t.str)
}

// 値レシーバ
func (t StrData) valExec() {
	fmt.Println(t.str)
}

func main() {
	vRecv := StrData{"value receiver"}
	pRecv := &StrData{"pointer receiver"}

        // メソッドを変数に代入する
	vExec := vRecv.valExec
	pExec := pRecv.ptrExec

        vExec()  // value receiver
        pExec()  // pointer receiver

        // 構造体に対して代入する
        vRecv.str = "redifinition"
        pRecv.str = "redifinition"

        vExec() // value receiverのまま変わらない
        pExec() // redifinitionに変更される
}


関連ページ