最も単純な形では、インターフェース型はメソッドのシグネチャの集まりです。
次は、AddとValueという2つのメソッドを含むインターフェース定義の例です。
type Counter interface {
Add(increment int)
Value() int
}
incrementのような仮引数の名前は、インターフェース定義から省略できますが、書いておくと読みやすくなることがよくあります。
Goのインターフェース名には、InterfaceやIという語は含めません。
その代わり、ReaderやStringerのように、erで終わることがよくあります。
インターフェースのメソッドを定義している型は、自動的に、暗黙のうちにそのインターフェースを「実装」します。
Goにはimplementsというキーワードはありません。
次の型は、上で見たCounterインターフェースを実装しています。
type Stats struct {
value int
// ...
}
func (s Stats) Add(v int) {
s.value += v
}
func (s Stats) Value() int {
return s.value
}
func (s Stats) SomeOtherMethod() {
// The type can have additional methods not mentioned in the interface.
}
インターフェースを実装するうえでは、メソッドが値レシーバーを持つかポインターレシーバーを持つかは関係ありません。 (これらについて自信がなければ、メソッドのコンセプトをもう一度見てみましょう。)
インターフェース型の値には、それらのメソッドを実装している任意の値を入れることができます。 [^1]
つまりStatsは、Counterインターフェースを期待するすべての場所で使えるようになりました。
func SetUpAnalytics(counter Counter) {
// ...
}
stats := Stats{}
SetUpAnalytics(stats)
// works because Stats implements Counter
インターフェースは暗黙のうちに実装されるので、1つの型が複数のインターフェースを簡単に実装できます。 必要なメソッドがすべて定義されていればよいのです。
Goには、とても特別なインターフェース型が1つあります。メソッドを1つも持たない空のインターフェース型です。
空のインターフェースはinterface{}のように書きます。
anyはinterface{}のエイリアスで、よりよく使われます。
空のインターフェースにはメソッドがないので、どの型も暗黙のうちにこれを実装しています。 これは、あらゆる値を汎用的に受け取る関数を定義するのに役立ちます。 その場合、関数の仮引数に空のインターフェース型を使います。
ベルリンにある新しい空港が、ロボット研究室のためにエンジニアを採用しました。そこで働き始めることになります。 空港には、ぎこちなくて、どこか人型に見えるロボットたちがいて、カスタマーサービスの改善に使おうとしています。
最初の仕事は、セルフチェックインカウンターでパスポートをスキャンした人に、その人の母語でロボットがあいさつできるようにするプログラムを書くことです。
ロボットは自分の能力に誇りを持っているので、いつも最初に自分が話せる言語を告げてから、その人にあいさつします。 たとえば、ドイツのパスポートをスキャンした場合、ロボットはこう言います。
I can speak German: Hallo Dietrich!
言語ごとのコードを自分で書くわけではないので、あとから他のエンジニアが簡単に言語を追加できるように、ロボットのコードを構成する必要があります。
まずは、2つのメソッドを持つインターフェースGreeterを定義します。
LanguageNameは、ロボットがその訪問者にあいさつする言語の名前(string)を返します。Greetは、訪問者の名前(string)を受け取り、特定の言語でのあいさつメッセージをstringで返します。次に、訪問者の名前と、Greeterインターフェースを実装しているものを受け取り、目的のあいさつの文字列を返す関数SayHelloを実装します。
たとえば、LanguageNameが"German"を返し、Greetが"Hallo {name}!"を返すドイツ語のGreeter実装を考えてみましょう。
SayHello("Dietrich", germanGreeter)
// => "I can speak German: Hallo Dietrich!"
次は、イタリアのパスポートをスキャンした人にロボットが対応できるようにします。
そのために、構造体Italianを作成し、タスク1で用意したGreeterインターフェースを満たすために必要な2つのメソッドを実装します。
イタリア語では、"Ciao {name}!"であいさつできます。
今日の仕事を終える前に、ポルトガル語であいさつする機能も仕上げておきましょう。
そのために、構造体Portugueseを作成し、ここでもGreeterインターフェースを満たすために必要な2つのメソッドを実装します。
ポルトガル語では、"Olá {name}!"であいさつできます。