インターフェース入門
CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 25/107。
Goにおけるインターフェースは、メソッドの実装を持たずに、メソッドのシグネチャのセットを定義します。それは型が何ができるかを記述するものであり、どのように行うかを記述するものではありません。インターフェース内のすべてのメソッドを実装する型は、自動的にそのインターフェースを満たします。
インターフェースの定義方法は以下の通りです。
type Speaker interface {
Speak() string
}この Speaker インターフェースは、実装するすべての型が文字列を返す Speak() メソッドを持つことを要求します。これにより、このメソッドを持つ任意の構造体は、Speaker が期待される場所であればどこでも使用できるようになります。
type Dog struct {
Name string
}
func (d Dog) Speak() string {
return d.Name + " says woof!"
}
type Cat struct {
Name string
}
func (c Cat) Speak() string {
return c.Name + " says meow!"
}DogとCatはどちらも、正しいシグネチャを持つSpeak()メソッドを持っているため、Speakerインターフェースを満たしています。これで、任意のSpeakerを受け入れる関数を記述できるようになります:
func MakeSound(s Speaker) {
fmt.Println(s.Speak())
}
func main() {
dog := Dog{Name: "Buddy"}
cat := Cat{Name: "Whiskers"}
MakeSound(dog) // Buddy says woof!
MakeSound(cat) // Whiskers says meow!
}インターフェースにより、基盤となる実装に関わらず、インターフェースの要件を満たすあらゆる型で動作する、柔軟で再利用可能なコードを記述できるようになります。
チャレンジ
簡単インターフェースによって異なる型が共通の動作を共有できることを示す、車両説明システムを構築しましょう。複数の車両タイプが満たすことができるインターフェースを作成し、それを使用してあらゆる車両を一律に説明できるようにします。
コードは2つのファイルに分けて構成します:
vehicles.go:Describe() stringという単一のメソッドを持つDescriberインターフェースを定義します。次に、このインターフェースを満たす2つの構造体を作成します:BrandとModelフィールド(どちらも文字列)を持つCarType(文字列) とGears(整数) フィールドを持つBicycle
Describe()メソッドを持つ必要があります。main.go: 任意のDescriberを受け取り、そのDescribe()メソッドを呼び出した結果を出力するPrintDescriptionという関数を作成します。入力から車両情報を読み取り、Car と Bicycle の両方を作成し、作成した関数を使用してそれぞれの説明を出力します。
以下の入力が提供されます:
- 1行目: 車のブランド (Car brand)
- 2行目: 車のモデル (Car model)
- 3行目: 自転車のタイプ (Bicycle type)
- 4行目: ギアの数 (整数)
Describe() メソッドは、以下の形式の文字列を返す必要があります:
- Car:
[Brand] [Model] - Bicycle:
[Type] bike with [Gears] gears
例えば、Toyota、Camry、Mountain、21 が与えられた場合、出力は以下のようになります:
Toyota Camry
Mountain bike with 21 gearsここでの重要なポイントは、PrintDescription 関数が Describe() メソッドを持つあらゆる型で動作するということです。それが Car なのか Bicycle なのか、あるいは後で追加する他の車両タイプなのかを関数が知る必要はありません。
チートシート
Goにおけるインターフェースは、実装を持たずにメソッドのシグネチャのセットを定義します。すべてのメソッドを実装する任意の型は、自動的にそのインターフェースを満たします。
インターフェースの定義:
type Speaker interface {
Speak() string
}必要なメソッドを実装する型は、インターフェースを満たします:
type Dog struct {
Name string
}
func (d Dog) Speak() string {
return d.Name + " says woof!"
}
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: "Buddy"}
cat := Cat{Name: "Whiskers"}
MakeSound(dog) // Buddy says woof!
MakeSound(cat) // Whiskers says meow!
}自分で試してみよう
package main
import (
"fmt"
)
// TODO: 任意の Describer を受け取り、
// その Describe() メソッドを呼び出した結果を出力する PrintDescription 関数を作成してください
func main() {
// 入力を読み込む
var carBrand string
var carModel string
var bicycleType string
var gears int
fmt.Scanln(&carBrand)
fmt.Scanln(&carModel)
fmt.Scanln(&bicycleType)
fmt.Scanln(&gears)
// TODO: 入力されたブランドとモデルを使用して Car を作成してください
// TODO: 入力されたタイプとギア数を使用して Bicycle を作成してください
// TODO: PrintDescription を使用して車の説明を出力してください
// TODO: PrintDescription を使用して自転車の説明を出力してください
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー