導入
インターフェース は「このメソッドを持っている型なら何でもいい」という約束です。具体的な型が何であるかを問わず、「〜できるもの」として扱えます。
説明
package main
import "fmt"
// String() を持つ型なら何でも Stringer として扱える
type Stringer interface {
String() string
}
type Dog struct{ Name string }
type Cat struct{ Name string }
func (d Dog) String() string { return d.Name + "(犬)" }
func (c Cat) String() string { return c.Name + "(猫)" }
func introduce(s Stringer) {
fmt.Println("これは " + s.String())
}
func main() {
introduce(Dog{Name: "ポチ"}) // これは ポチ(犬)
introduce(Cat{Name: "タマ"}) // これは タマ(猫)
}
type Stringer interface { String() string }… 「String() stringメソッドを持つ」という条件を表す型。DogもCatもString()を持つので、どちらも自動的にStringerとして扱えます(「implements」と宣言する必要はありません)。introduceは具体的な型を知らず、「String()できるもの」だけを受け取ります。
このように「宣言なしで、メソッドさえ揃えば適合する」仕組みを ダックタイピング と呼びます。犬と猫を同じ関数で扱えるのが、インターフェースの力です。
やってみよう
新しく type Bird struct{ Name string } と、その String() メソッドを足せば、introduce(Bird{...}) もそのまま動きます。introduce 側を1行も変えずに対応できるのがインターフェースの狙いです。