Go言語のインターフェースは、他のオブジェクト指向言語(JavaやC++など)とは異なり、「明示的に実装を宣言しない」という特徴があります。この設計は、ダックタイピングの考え方に基づいており、Goならではの柔軟なプログラミングスタイルを実現しています。
本記事では、Goのインターフェースの仕組みやダックタイピングとの関係について解説し、コード例とともにその利点を紹介します。
Goのインターフェースは、以下の特徴を持っています。
✅ 明示的な実装宣言が不要
✅ 「ある型が何をできるか(メソッドを持っているか)」のみを基準に適合を判断
✅ 疎結合で柔軟なコードが書ける
たとえば、以下のコードでは Dog
型が Speaker
インターフェースを満たしていますが、implements
のような明示的な宣言はありません。
gopackage main
import "fmt"
// Speaker インターフェース
type Speaker interface {
Speak() string
}
// Dog 構造体
type Dog struct {
Name string
}
// Speak メソッドを実装
func (d Dog) Speak() string {
return d.Name + " says: Woof!"
}
// Speaker を受け取る関数
func MakeSound(s Speaker) {
fmt.Println(s.Speak())
}
func main() {
dog := Dog{Name: "Rex"}
MakeSound(dog) // Rex says: Woof!
}
このコードでは、Dog
型が Speaker
インターフェースを満たしているため、MakeSound(dog)
のように Speaker
型の引数として渡すことができます。
この「メソッドがあれば自動的に適合する」という仕組みは、ダックタイピング に似ています。
ダックタイピング(Duck Typing) とは、
「もし何かがアヒルのように歩き、アヒルのように鳴くなら、それはアヒルだと考えるべき」
という考え方です。
プログラミングにおいては、型が何であるかよりも、その型がどのようなメソッドを持っているかを重視する ことを意味します。
Goのインターフェースはまさにこの考え方を採用しており、型宣言なしに、メソッドの有無だけで適合を判断 します。
たとえば、Dog
だけでなく Cat
も Speak
メソッドを持っていれば、Speaker
インターフェースを満たします。
gopackage main
import "fmt"
// Speaker インターフェース
type Speaker interface {
Speak() string
}
// Dog 構造体
type Dog struct {
Name string
}
func (d Dog) Speak() string {
return d.Name + " says: Woof!"
}
// Cat 構造体
type Cat struct {
Name string
}
func (c Cat) Speak() string {
return c.Name + " says: Meow!"
}
func MakeSound(s Speaker) {
fmt.Println(s.Speak())
}
func main() {
dog := Dog{Name: "Rex"}
cat := Cat{Name: "Mittens"}
MakeSound(dog) // Rex says: Woof!
MakeSound(cat) // Mittens says: Meow!
}
このように、Dog
も Cat
も Speaker
インターフェースに適合しているため、MakeSound
関数に渡すことができます。
「暗黙的に適合するのは便利だけど、可読性のために明示的に宣言したい」と思うこともあります。その場合、コンパイル時にインターフェース適合をチェックする方法 があります。
gopackage main
// Speaker インターフェース
type Speaker interface {
Speak() string
}
// Dog 構造体
type Dog struct {
Name string
}
// 明示的に Speaker を満たすことを宣言(コンパイル時チェック)
var _ Speaker = (*Dog)(nil)
// Speak メソッドを実装
func (d Dog) Speak() string {
return d.Name + " says: Woof!"
}
この var _ Speaker = (*Dog)(nil)
は、
Speak
メソッドを実装していなければコンパイルエラーになるという役割を持っています。
言語 | インターフェースの実装方法 |
Java / C++ | implements InterfaceName や public class Dog : Speaker を明示的に宣言する必要がある |
Go | implements などの明示的な宣言は不要。メソッドの有無だけでインターフェース適合が判断される |
✅ 「型」よりも「できること」を重視する設計
✅ メソッドがあるかどうかで適合が決まる(ダックタイピング)
✅ 明示的な宣言が不要なため、疎結合なコードを書きやすい
✅ 可読性のために _ Speaker = (*Dog)(nil)
のようにチェックを追加できる
Go の「暗黙的に適合する柔軟なインターフェース設計」は、最初は違和感があるかもしれませんが、慣れるとシンプルで強力な設計思想 だと感じられるはずです! 🚀