2
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GoのinterfaceをJavaの感覚で学んだらむしろややこしくなった

Posted at

はじめに

はじめまして。現在Goを学習中のrikutoです。

この記事は、Javaの知識を引きずったままGoのinterfaceを学んで混乱した経験をもとに、自分なりに考えを言語化し、整理するために書いたものです。

同じようにJava経験者でGoを学んでいる方の参考になれば嬉しいです。
もし内容に誤りや改善点などがあれば、コメントで教えていただけると嬉しいです。

JavaとGoのinterface

Javaのinterfaceについて

Javaにおけるinterfaceは、「クラスが実装するもの」 という認識が強いと思います。

class Sample implements Interface {
    // 実装
}
  • implementsを明示的に書く
  • 「このクラスはinterfaceを実装している」と宣言する

そのため、interfaceは、実装する対象であり、関係性をはっきり示すもの というイメージを持っていました。


Goのinterfaceについて

一方、Goのinterfaceは書き方からして大きく異なります。

type sample interface {
    method()
}
  • Goにはimplementsというキーワードが存在しません
  • struct側でも、「このinterfaceを実装しています」と書くこともありません

Goでは、
interfaceに定義されたメソッドを持っていれば、そのinterfaceを満たしている
という考え方が取られています。

なぜ混乱したのか?

混乱した原因はシンプルで、
「interfaceは実装するものだ」という思い込みでした。

Javaでは、

  • interfaceを実装する
  • implementsを書く
  • 関係性を明示する

という流れが当たり前です

その感覚のままGoのコードを見ると、

  • どこでinterfaceを実装しているのかが分からない
  • いつinterfaceを満たしたことになるのか分からない

と感じてしまいます。

しかしGoは、
実装しているかどうかを宣言するのではなく、
必要なメソッドを持っているかどうかだけを見る
という思想です。

この違いに気づくまで、
Goのinterfaceが理解できませんでした。

ただ、この違いを明確にしたことで、Goのinterfaceの考え方が整理できました。

実際にGoのinterfaceを書いてみる

①interfaceの宣言

type Printer interface {
    Print()
}

「Printできるもの」を表すinterfaceです。
ここではメソッド名のみを宣言しています。


②同じ振る舞い(Print)を持つstructを宣言

type ConsolePrinter struct{}

func (c ConsolePrinter) Print() {
    fmt.Println("print to console")
}
type FilePrinter struct{}

func (f FilePrinter) Print() {
    fmt.Println("print to file")
}
  • どちらもPrint()を持つ
  • interfaceを意識した記述は一切ない

③interface型を引数に取る関数を宣言

func ExecutePrint(p Printer) {
    p.Print()
}

④呼び出し側

func main() {
    c := ConsolePrinter{}
    f := FilePrinter{}

    ExecutePrint(c)
    ExecutePrint(f)
}

ExecutePrint 関数は、Printer interface 型を引数に取ります。
しかし、実際に渡しているのは、ConsolePrinterFilePrinter 型の変数です。

一見すると、interface 型ではない値を渡しているように見えます。
それでもエラーにならないのは、
どちらの型も Print() メソッドを持っており、
Printer interface の条件を満たしているためです。

Goでは、
「この interface を実装しています」と宣言する必要はありません。
必要なメソッドを持っていれば、その時点で interface を満たします。

まとめ : Goのinterfaceは「実装するもの」ではない

Javaを最初に学んだ立場からGoのinterfaceを見ると、
「どこでimplementsしているのか分からない」
「なぜinterface型として扱えるのか分からない」
のように混乱しやすいと感じました。

その原因は、
interfaceは実装するものだ、という思い込みにありました。

Goのinterfaceは、
「このinterfaceを実装しています」と宣言するものではなく、必要なメソッドを持っているかどうかだけで判断されます。

つまりGoのinterfaceは、
クラスの関係性を表すものではなく、
振る舞い(何ができるか)を表すものです。

このように捉えることで、
Goのinterfaceの考え方が理解できました。

2
6
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
2
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?