38
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Go 言語】interface のポインタからメソッドコールできないのはなぜ?

Last updated at Posted at 2021-03-18

結論

簡潔に言うと「interface を指すポインタは interface を実装した構造体のポインタのポインタになるから」です。
これだけではよくわからないので詳しくみていきましょう。

interface のポインタからメソッドコールができないとは?

interface の Mammal とそれを実装した Human という構造体を考えましょう。

type Mammal interface {
	GetAge() int
}

type Human struct {
	Age int
}

func (h *Human) GetAge() int {
	return h.Age
}

この時、以下のように Mammal というインターフェースのポインタから GetAge() をコールしようとするとコンパイルエラーになってしまいます。

func Foo(human *Mammal) {
	_ = human.GetAge()  // コンパイルエラー
}

GetAge() をコールするためには *Mammal ではなく Mammal を引数に取る必要があります。

func Foo(human Mammal) {
	_ = human.GetAge()
}

そもそも Go 言語の interface とは?

以下のブログにわかりやすく Go の interface とは何かが説明されています。ざっくりまとめると、 interface は型情報と値情報をフィールドに持った構造体になります。これらの型情報と値情報は interface を受ける変数に代入されることで、動的に変化するようです。

interface のポインタ

変数 human が interface の Mammal そのものを指す場合、以下の図のようになり、構造体の実体からはポインタに当たるものなので GetAge() をコールすることができます。

スクリーンショット 2021-03-19 7.50.45.png

しかし、human が interface の Mammal のポインタの場合、下の図を見ると、構造体の実体からはポインタのポインタに当たるものになってしまっているので GetAge() をコールすることができなかった訳です。

スクリーンショット 2021-03-19 7.56.23.png

ポインタのポインタは 1 段階デリファレンスしてやれば最終的な参照先のメソッドをコールすることができます。つまり、interface のポインタはデリファレンスしてやることでメソッドコールが可能になると言うことです。

func Foo(human *Mammal) {
	_ = (*human).GetAge()
}
38
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?