1
0

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 1 year has passed since last update.

Goにおけるレシーバの型について

Posted at

下記の様なコードがあるとします。


package main

import "fmt"

type Greet interface {
	sayGreet() string
}

type Hello struct {
	Message string
}

func (h *Hello) sayGreet() string {
	return h.Message
}

func createGreet() Greet {
	return Hello{Message: "こんにちは"}//ここでコンパイルエラー
}

func main() {
	g := createGreet()
	fmt.Println(g.sayGreet())
}

今このコードは、createGreet関数のreturnの箇所でコンパイルエラーを起こしています。

なぜなのか。

createGreet関数の返り値はGreetインターフェイスです。

ということは

return Hello{Message: "こんにちは"}

上記で返される返り値がGreetインターフェイスを実装している型であれば問題ないはずです。

func (h *Hello) sayGreet() string {
	return h.Message
}

上記の箇所で、Hello構造体はstring型を返すsayGreet()メソッドを実装しているため、HelloはGreetインターフェイスを実装しているように見えます。

しかし、よく見るとレシーバは 「(h *Hello)」 となっており、「Hello構造体を参照しているポインタ型」となっています。

あくまで、sayGreet()をメソッドとして保持している型は「Hello型」ではなく、「Hello型を参照しているポインタ型」となります。

ですので、createGreet()の返り値は「Hello型」ではなく、「Hello型を参照しているポインタ型」にしなければいけません。

下記のように修正します。

func createGreet() Greet {
	return Hello{Message: "こんにちは"}//Hello型を返している。
}

   ⬇️ 修正

func createGreet() Greet {
	return &Hello{Message: "こんにちは"}//Hello型を参照しているポインタ型を返している。
}

これでコンパイルエラーが解消され、プログラムが動くようになりました。

なお、新たな疑問として

func (h *Hello) sayGreet() string {
	return h.Message
}

hはポインタ型(アドレスが格納されている。)なのに、なぜMessageをとってこれるのか?

これはGoが自動的にポインタの参照先の構造体からMessageの内容を取得してきてくれるからとなります。

もちろん下記のように、愚直に記載してもプログラムは正しく動作します。

func (h *Hello) sayGreet() string {
	return (*h).Message //hが参照している構造体そのものからMessageを取得
}

 

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?