【Go入門】メソッドセット(Method sets)

Go
スポンサーリンク

Go言語のメソッドセット(Method sets)を見て行きます。

メソッドセットはtypeに結びつけられたメソッドを定めます。特定のtypeのメソッドがメソッドセットということですが、具体的なコードで動きをみていきましょう。

スポンサーリンク

メソッドセット(Method sets)の値の処理

メソッドセットはその名の通りメソッドが関係するので、こちらのメソッドの内容も確認しておきましょう。

メソッドセットの動きには次のような特徴があります。

非ポインタのレシーバの場合、非ポインタ、ポインタ両方の値で機能します。

ポインタのレシーバの場合、ポインタの値でのみ機能します。

これらの動きの違いを具体的なコードで見て行きます。

レシーバと値にそれぞれポインタ、非ポインタをとって4つの組み合わせで動きを確認することができます。

スポンサーリンク

非ポインタのレシーバの場合

順にパターンを分けて具体的なコードで見ていきましょう。コードにはインターフェイスも使っているので確認しておきましょう。

円の面積を求めるコードでやって行きましょう。

まずはレシーバに非ポインタをとる場合からです。

非ポインタのレシーバと非ポインタの値の処理

こちらは非ポインタの値の処理です。

package main

import (
	"fmt"
	"math"
)

type circle struct {
	radius float64
}

type area interface {
	calcArea() float64
}

func (c circle) calcArea() float64 {
	return math.Pi * c.radius * c.radius
}

func calcResult(a area) {
	fmt.Println("円の面積は", a.calcArea())
}

func main() {
	c1 := circle{3}
	calcResult(c1)
}

円周率を使うのMathパッケージをimportしています。

typeでcircle型のstructを作ります。フィールドに半径radiusをとりfloat64型としています。

インターフェイス型のareaを作って、メソッドに面積計算のcalcArea()を定義し、戻り値にfloat64を指定します。

このメソッドを、半径をレシーバ(ここでは非ポインタ)にとって定義しています。円の面積は円周率としてMath.Piを使って計算しています。

インターフェイスを引数にとってcalcResult()関数で、メソッドを実行して計算結果を出力します。

半径3を指定して、非ポインタとして値を計算しています。

計算結果はこうなります。

円の面積は 28.274333882308138

このコード自体は、インターフェイスで扱った処理と同じです。

非ポインタのレシーバとポインタの値の処理

今度はポインタの値の処理です。

上のコードを次のように変更します。

package main

import (
	"fmt"
	"math"
)

type circle struct {
	radius float64
}

type area interface {
	calcArea() float64
}

func (c circle) calcArea() float64 {
	return math.Pi * c.radius * c.radius
}

func calcResult(a area) {
	fmt.Println("円の面積は", a.calcArea())
}

func main() {
	c2 := circle{3}
	calcResult(&c2)  // ポインタの値の処理
}

全体のコードは先ほどのコードと同じですが、計算時に渡す値が違います。

ここでは、ポインタの値を処理させるために&を付けています。

計算結果は同じです。

円の面積は 28.274333882308138
スポンサーリンク

ポインタのレシーバの場合

今度は、レシーバにポインタをとる場合を見ていきましょう。

上のコードを修正して利用します。

ポインタのレシーバとポインタの値の処理

ポインタの値の処理を見て行きましょう。

次のコードになります。

package main

import (
	"fmt"
	"math"
)

type circle struct {
	radius float64
}

type area interface {
	calcArea() float64
}

func (c *circle) calcArea() float64 {     // レシーバにポインタ
	return math.Pi * c.radius * c.radius
}

func calcResult(a area) {
	fmt.Println("円の面積は", a.calcArea())
}

func main() {
	c3 := circle{3}
	calcResult(&c3)  // ポインタの値の処理
}

レシーバにポインタを渡しています。

処理にはポインタの値を渡しています。

計算結果は同じです。

円の面積は 28.274333882308138

ポインタのレシーバと非ポインタの値の処理

今度は非ポインタの値の処理を見て行きましょう。

次のコードになるのですが…

package main

import (
	"fmt"
	"math"
)

type circle struct {
	radius float64
}

type area interface {
	calcArea() float64
}

func (c *circle) calcArea() float64 {
	return math.Pi * c.radius * c.radius
}

func calcResult(a area) {
	fmt.Println("円の面積は", a.calcArea())
}

func main() {
	c4 := circle{3}
	calcResult(c4)    // 非ポインタの値の処理
}

上のコードとの違いは、実行時の値の処理に、非ポインタの値を渡しているところです。

実行するとこうなります。

cannot use c4 (type circle) as type area in argument to calcResult:
circle does not implement area (calcArea method has pointer receiver)

このようにエラーになります。

最初に、「ポインタのレシーバの場合、ポインタの値でのみ機能します」とのべたことの確認になります。

これを処理するには、値の処理を次のように変更します。

func main() {
	c4 := circle{3}
	// calcResult(c4)
	fmt.Println(c4.calcArea())
}

このように、インターフェイスの処理をすることで値を計算することができます。

28.274333882308138
スポンサーリンク

最後に

ここでは、Go言語のメソッドセット(Method sets)を扱いました。

メソッドセットは特定のtypeに結びつけられたメソッドになります。

メソッドセットは、非ポインタのレシーバの場合は非ポインタ、ポインタ両方の値で機能し、ポインタのレシーバの場合はポインタの値でのみ機能します。

Go
スポンサーリンク
CodeGraffitiをフォローする

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