Menu
Coddy logo textTech

インターフェース入門

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!"
}

DogCatはどちらも、正しいシグネチャを持つ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!
}

インターフェースにより、基盤となる実装に関わらず、インターフェースの要件を満たすあらゆる型で動作する、柔軟で再利用可能なコードを記述できるようになります。

challenge icon

チャレンジ

簡単

インターフェースによって異なる型が共通の動作を共有できることを示す、車両説明システムを構築しましょう。複数の車両タイプが満たすことができるインターフェースを作成し、それを使用してあらゆる車両を一律に説明できるようにします。

コードは2つのファイルに分けて構成します:

  • vehicles.go: Describe() string という単一のメソッドを持つ Describer インターフェースを定義します。次に、このインターフェースを満たす2つの構造体を作成します:
    • BrandModel フィールド(どちらも文字列)を持つ Car
    • Type (文字列) と 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

例えば、ToyotaCamryMountain21 が与えられた場合、出力は以下のようになります:

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 を使用して自転車の説明を出力してください
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン