Go練習問題3-10:インターフェースを理解しよう

記事内に商品プロモーションを含む場合があります

Go言語の初心者向け問題3-10:インターフェースを理解しよう

この問題を解くために必要な知識:
レベル1~2の知識関数の定義と呼び出し関数の戻り値と複数の戻り値関数の可変長引数無名関数(匿名関数)クロージャ構造体の定義コンストラクタ関数構造体の埋め込みメソッドの定義とレシーバインターフェース型アサーション型スイッチ

<<前の問題 問題集Top 次の問題>>

Go言語の文法「インターフェース」とは





ここではインターフェースの意味や使い方を復習します。必要ない方はここをクリックして練習問題へ飛びましょう。

Go言語のインターフェースは、柔軟で強力な機能を提供します。これは、メソッドの集合を定義し、そのメソッドを持つすべての型がそのインターフェースを実装したと見なされる仕組みです。

インターフェースを使用することで、異なる型に対して同じ操作を実行できるコードを書くことができます。

インターフェースの定義と使用

例えば、以下のようなSpeakerインターフェースを定義できます。

type Speaker interface {
    Speak()
}

このインターフェースは、Speakメソッドを持つすべての型が実装できます。次に、Speakerインターフェースを実装する型を作成し、実際に使用してみましょう。

type Dog struct {}

func (d Dog) Speak() {
    fmt.Println("Woof!")
}

func main() {
    var s Speaker
    s = Dog{}
    s.Speak() // "Woof!" が出力されます
}

空インターフェース

Goには、すべての型を受け入れる「空インターフェース」があります。空インターフェースはinterface{}と書き、すべての型が実装していることになります。

これにより、任意の型を引数として受け取る汎用的な関数を作成できます。

func PrintAnything(value interface{}) {
    fmt.Println(value)
}

func main() {
    PrintAnything(42)          // "42" が出力されます
    PrintAnything("Hello")     // "Hello" が出力されます
}

このように、Goのインターフェースは非常に柔軟で、異なる型に対して一貫した操作を提供するのに役立ちます。

Go練習問題3-10:ペットの鳴き声を統一的に扱うプログラムを作成しよう

インターフェースを使って、異なる種類のペット(犬、猫、鳥)の鳴き声を統一的に扱うプログラムを作成しましょう。

各ペットの種類に応じた鳴き声を出力するメソッドを持つ構造体を作成し、それらをインターフェースを使って一元的に処理します。

この問題の要件

以下の要件に従ってコードを完成させてください。

  • Animalというインターフェースを定義し、その中にSpeak()メソッドを定義すること。Speak()メソッドは、ペットの鳴き声を文字列として返すこと。
  • Dog, Cat, Birdという3つの構造体を作成し、それぞれにNameという文字列型のフィールドを持たせること。
  • Dog, Cat, Bird構造体に、それぞれSpeak()メソッドを実装し、犬は「ワンワン」、猫は「ニャーニャー」、鳥は「チュンチュン」と鳴くようにすること。
  • それぞれの構造体をインスタンス化し、makeAnimalSpeak()という関数に渡して鳴き声を出力すること。この関数はAnimalインターフェースを受け取り、Speak()メソッドを呼び出してその結果を出力すること。

ただし、以下のような実行結果となるコードを書くこと。

*****↓↓正解コードの実行結果の例↓↓*****

ワンワン
ニャーニャー
チュンチュン

この問題を解くヒント

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。

1. import文
 1.1. fmtパッケージのインポート

2. インターフェースの定義
 2.1. Animalインターフェースの定義
 2.2. Speak()メソッドの定義

3. 構造体の定義とメソッド
 3.1. Dog構造体の定義
  3.1.1. Nameフィールドの定義
  3.1.2. Speak()メソッドの実装(Dog構造体用)
 3.2. Cat構造体の定義
  3.2.1. Nameフィールドの定義
  3.2.2. Speak()メソッドの実装(Cat構造体用)
 3.3. Bird構造体の定義
  3.3.1. Nameフィールドの定義
  3.3.2. Speak()メソッドの実装(Bird構造体用)

4. 関数の定義
 4.1. makeAnimalSpeak関数の定義
  4.1.1. Animalインターフェースを受け取り、Speak()メソッドを呼び出す処理

5. main関数の定義
 5.1. Dog構造体のインスタンス化
 5.2. Cat構造体のインスタンス化
 5.3. Bird構造体のインスタンス化
 5.4. makeAnimalSpeak関数の呼び出し
  5.4.1. Dogインスタンスの鳴き声を出力
  5.4.2. Catインスタンスの鳴き声を出力
  5.4.3. Birdインスタンスの鳴き声を出力

ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

package main

import "fmt"

// Animalインターフェースは、全てのペットが持つべきメソッドを定義します。
type Animal interface {
    Speak() string // Speakメソッドは、ペットの鳴き声を返します。
}

// Dog構造体は犬を表します。
type Dog struct {
    Name string
}

// SpeakメソッドはDogのインスタンスに関連付けられ、犬の鳴き声を返します。
func (d Dog) Speak() string {
    /* 【穴埋め問題1】
    ここに犬の鳴き声「ワンワン」を返すコードを書いてください。
    */
}

// Cat構造体は猫を表します。
type Cat struct {
    Name string
}

// SpeakメソッドはCatのインスタンスに関連付けられ、猫の鳴き声を返します。
func (c Cat) Speak() string {
    /* 【穴埋め問題2】
    ここに猫の鳴き声「ニャーニャー」を返すコードを書いてください。
    */
}

// Bird構造体は鳥を表します。
type Bird struct {
    Name string
}

// SpeakメソッドはBirdのインスタンスに関連付けられ、鳥の鳴き声を返します。
func (b Bird) Speak() string {
    /* 【穴埋め問題3】
    ここに鳥の鳴き声「チュンチュン」を返すコードを書いてください。
    */
}

// 各ペットの鳴き声を表示する関数
func makeAnimalSpeak(a Animal) {
    /* 【穴埋め問題4】
    ここにインターフェースのSpeakメソッドを呼び出してペットの鳴き声を表示するコードを書いてください。
    */
}

func main() {
    // 各ペットを作成します。
    dog := Dog{Name: "ポチ"}
    cat := Cat{Name: "タマ"}
    bird := Bird{Name: "ピーちゃん"}

    // 各ペットの鳴き声を表示します。
    makeAnimalSpeak(dog)  // 出力: ワンワン
    makeAnimalSpeak(cat)   // 出力: ニャーニャー
    makeAnimalSpeak(bird)  // 出力: チュンチュン
}

 

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。

解答例と解説

この問題の一つの正解例とそのコードの解説を以下に示します。

正解コードの例

例えば以下のようなプログラムが考えられます。

package main

import "fmt"

// Animalインターフェースは、全てのペットが持つべきメソッドを定義します。
type Animal interface {
    Speak() string // Speakメソッドは、ペットの鳴き声を返します。
}

// Dog構造体は犬を表します。
type Dog struct {
    Name string
}

// SpeakメソッドはDogのインスタンスに関連付けられ、犬の鳴き声を返します。
func (d Dog) Speak() string {
    return "ワンワン" // 犬の鳴き声
}

// Cat構造体は猫を表します。
type Cat struct {
    Name string
}

// SpeakメソッドはCatのインスタンスに関連付けられ、猫の鳴き声を返します。
func (c Cat) Speak() string {
    return "ニャーニャー" // 猫の鳴き声
}

// Bird構造体は鳥を表します。
type Bird struct {
    Name string
}

// SpeakメソッドはBirdのインスタンスに関連付けられ、鳥の鳴き声を返します。
func (b Bird) Speak() string {
    return "チュンチュン" // 鳥の鳴き声
}

// 各ペットの鳴き声を表示する関数
func makeAnimalSpeak(a Animal) {
    fmt.Println(a.Speak())
}

func main() {
    // 各ペットを作成します。
    dog := Dog{Name: "ポチ"}
    cat := Cat{Name: "タマ"}
    bird := Bird{Name: "ピーちゃん"}

    // 各ペットの鳴き声を表示します。
    makeAnimalSpeak(dog)  // 出力: ワンワン
    makeAnimalSpeak(cat)   // 出力: ニャーニャー
    makeAnimalSpeak(bird)  // 出力: チュンチュン
}

正解コードの解説

このコードは、Go言語の重要な概念である「インターフェース」を使用しています。

インターフェースは、異なる型に共通のメソッドを持たせるための仕組みで、Goにおけるポリモーフィズムを実現するための基本的な機能です。

import文

import "fmt"

ここでは、標準ライブラリのfmtパッケージをインポートしています。このパッケージは、コンソールにテキストを出力するために使用されます。

インターフェースの定義

type Animal interface {
    Speak() string
}

Animalというインターフェースを定義しています。このインターフェースは、Speak()というメソッドを持つことを要求します。

Speak()メソッドは、各動物の鳴き声を文字列として返す機能を持ちます。

Dog構造体の定義

type Dog struct {
    Name string
}

Dog構造体は、犬を表すデータ型です。Nameというフィールドがあり、これは犬の名前を表します。

Dog構造体のメソッドの定義

func (d Dog) Speak() string {
    return "ワンワン"
}

Dog構造体にSpeak()メソッドを実装しています。このメソッドは、Dog型のインスタンスが「ワンワン」と鳴くことを意味します。

Cat構造体の定義とメソッドの実装

type Cat struct {
    Name string
}

func (c Cat) Speak() string {
    return "ニャーニャー"
}

Cat構造体は猫を表し、Speak()メソッドは「ニャーニャー」と鳴くことを定義します。

Bird構造体の定義とメソッドの実装

type Bird struct {
    Name string
}

func (b Bird) Speak() string {
    return "チュンチュン"
}

Bird構造体は鳥を表し、Speak()メソッドは「チュンチュン」と鳴くことを定義します。

インターフェースを使用する関数の定義

func makeAnimalSpeak(a Animal) {
    fmt.Println(a.Speak())
}

makeAnimalSpeak関数は、Animalインターフェースを引数に取り、そのSpeak()メソッドを呼び出して鳴き声を出力します。

ここで重要なのは、DogCatBirdのいずれの型でも、この関数に渡せることです。これがインターフェースの強力なポイントです。

main関数

func main() {
    dog := Dog{Name: "ポチ"}
    cat := Cat{Name: "タマ"}
    bird := Bird{Name: "ピーちゃん"}

    makeAnimalSpeak(dog)
    makeAnimalSpeak(cat)
    makeAnimalSpeak(bird)
}

main関数では、DogCatBirdのインスタンスを作成し、それぞれの鳴き声を出力しています。

このコードを通じて、Goのインターフェースがどのように異なる構造体を扱い、共通のメソッドを実行するかを学ぶことができます。

インターフェースは、Goの柔軟性と拡張性を高める非常に重要な機能です。

<<前の問題 問題集Top 次の問題>>

この問題への質問・コメント

この問題を作成するにあたりAIを活用しています。

問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。






    Go練習問題集へ戻る
    トップページへ戻る