まず最初に
とあるインターンでGoに触れる機会があり、「interface、レシーバー、暗黙的インターフェースとは何か、どのように活用されているのか」が気になって調べていくうちに、かなりの時間を費やしてしまいました。
今後、他の方が調べる時間を短縮してもらえるよう、私が理解するのに役立った視点を共有します。
私の場合、Javaのimplementsの概念から考えると理解しやすかったので、その比較を通して説明します。
その前に前提知識であるGoのinterfaceとレシーバーについて解説させていただきます。
対象者
型やclassを大体理解している方で、Goのinterfaceやレシーバーに触れるがどう使えばいいのかイメージがしづらい方向けです。
interfaceとは?
この型は何ができるか(どんなメソッドを持つか)だけを定義し中身は書かない。
type Greeter interface {
Greet(name string) string // メソッド名(引数名 型) 返り値の型
}
レシーバーとは?
Goのメソッド定義は、関数の前に(変数名 型)という形でレシーバーを書きます。
type User struct {
Name string
}
// uがレシーバー
func (u User) Greet() string {
retrun "Hello, " + u.Name
}
- uがレシーバー変数
- Userがレシーバー型(このメソッドの属する型)
→この場合、GreetはUser型のメソッドになる。
User型のメソッドになったので以下のように使用ができる
func main() {
user := User{Name: "Taro"}
fmt.Println(user.Greet()) // Hello, Taro
}
暗黙的インターフェースとは?
必要なメソッドさえ揃っていれば、宣言しなくても自動的に「実装した」とみなされる
仕組み
初めて聞くと馴染みがありませんし、私は「ファ!?」ってなりました。
ですが、大丈夫です。優しく解説していきます。
実装例
Javaの場合
interface Greeter {
String greet(String name);
}
// 「EnglishGreeterクラスはGreeterを実装している」と宣言
class EnglishGreeter implements Greeter {
public String greet(String name) {
return "Hello, " +name;
}
}
implements Greeterと明示して、「EnglishGreeterクラスは Greeterを実装していますよ」と宣言している。
Javaでは、インターフェースを使うためには、implementsを使用して、「これを実装する」と明示的に書く。
Goの場合
package main
import (
"fmt"
)
// ①インターフェース(ルール)を定義
// 「Greet(string) stringというメソッドを持っている型はGreeterとして扱える」
type Greeter interface {
Greet(name string) string
}
// ② EnglishGreeter型を定義
type EnglishGreeter struct{}
// ③ EnglishGreeterにGreetメソッドを定義
// これで EnglishGreeter は自動的に Greeter を実装していると“みなされる”
func (e EnglishGreeter) Greet(name string) string {
return "Hello, " + name
}
// ④ Greeterを引数に受け取る関数
func SayHello(g Greeter) {
fmt.Println(g.Greet("Michel"))
}
func main() {
// EnglishGreeterはGreetを持っているのでGreeterとして渡せる
eg := EnglishGreeter{}
SayHello(eg) // 出力:Hello, Michel
}
EnglishGreeter
はGreetメソッドを持っているので、明示的に書かなくてもGreeterを実装していることになる
↓
Greet(string)を持っている型ならGreeterだとみなす
この仕組みがGoの暗黙的インターフェース実装です。
Javaのimplementから入ると、Goの暗黙的インタフェースが直感的に理解できたのではないでしょうか?
まとめ
Goの暗黙的インターフェースが分かりづらかったのは、私自身がimplementsの概念を深く理解していなかったことが大きな要因だと感じています。
近年の言語(PythonやGoなど)は、型や実装宣言を省くことができてしまう設計が多く、その分、初学者がプログラミングの基礎概念を意識しづらいと感じます。
私の周囲では、CやJavaなど、構造や型を明示的に扱う言語を経験したエンジニアほど、抽象化の背後にある仕組みを理解しており、応用時のつまずきが少ない傾向を感じています。こうした基礎経験が、本質的な課題への集中にもつながっているのだと思います。
もし内容が分かりづらい点や、「こう書いた方が分かりやすい」という改善案、または他の理解方法や実装例があれば、ぜひ教えていただけると幸いです。