Menu
Coddy logo textTech

メソッドの昇格

CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 36/107。

struct の埋め込みによってフィールドが外側の struct に昇格されるのと同じように、Go は埋め込まれた型のメソッドも昇格させます。つまり、埋め込まれた struct に定義されたメソッドを、外側の struct 上で直接呼び出すことができます。

type Engine struct {
    Horsepower int
}

func (e Engine) Start() string {
    return "Engine started"
}

type Car struct {
    Model string
    Engine  // 埋め込み
}

CarEngine を埋め込んでいるため、Start() method は自動的に昇格されます:

func main() {
    c := Car{
        Model:  "Sedan",
        Engine: Engine{Horsepower: 200},
    }
    
    fmt.Println(c.Start())         // エンジンが始動しました
    fmt.Println(c.Engine.Start())  // これも動作します
}

この昇格には、interface にとって重要な結果があります。埋め込み型が interface を満たしている場合、外側の型も自動的にその interface を満たします。

type Starter interface {
    Start() string
}

func Ignite(s Starter) {
    fmt.Println(s.Start())
}

func main() {
    c := Car{Model: "Sedan", Engine: Engine{Horsepower: 200}}
    Ignite(c)  // Car は Engine を通じて Starter を満たす
}

Car 型は Starter を明示的に実装していませんが、埋め込まれた Engine に必要なメソッドがあるため、インターフェースを満たします。これが、Go が従来の継承を使わずに動作の再利用を実現する方法です。

challenge icon

チャレンジ

簡単

埋め込み型のメソッドが外側の型にどのように昇格されるか、またそれによってコンポジションを通じた interface の満足がどのように可能になるかを示す音楽プレーヤーシステムを構築しましょう。

コードを2つのファイルに分けて整理します。

  • audio.go:音楽プレーヤーの構成要素を作成します。
    • AudioPlayer struct:Brand field(string)と、[Brand] playing audio を返す Play() string method
    • Playable interface:Play() string method を要求します
    • Smartphone struct:AudioPlayer を埋め込んだ Model field を持ちます
    • Tablet struct:AudioPlayer を埋め込んだ Model field を持ちます
  • main.go:任意の Playable を accepts し、Play() を calling した result を returns する StartPlayback という名前の function を作成します。入力からデバイス情報を読み取り、Smartphone と Tablet の両方を作成します。そして、どちらの型も自身で明示的に Play() を実装していないにもかかわらず、埋め込まれた AudioPlayer を通じて Playable interface を満たすことを示します。

次の入力が提供されます。

  • 1行目:Smartphone の model 名
  • 2行目:Smartphone の audio brand
  • 3行目:Tablet の model 名
  • 4行目:Tablet の audio brand

各デバイスについて、その model を出力した後、StartPlayback に渡した result を出力します。

たとえば、iPhone 15Apple AudioiPad ProBeats が与えられた場合、出力は次のようになります。

iPhone 15
Apple Audio playing audio
iPad Pro
Beats playing audio

AudioPlayerPlay() method が各外側の型に自動的に昇格されるため、追加のコードなしで Playable interface を満たし、Smartphone と Tablet の両方を StartPlayback に渡せることに注目してください。

自分で試してみよう

package main

import (
	"bufio"
	"fmt"
	"os"
)

// TODO: 任意の Playable を受け取る StartPlayback 関数を作成する
// そして Play() を呼び出した結果を返す

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// スマートフォンのモデルを読み取る
	scanner.Scan()
	smartphoneModel := scanner.Text()
	
	// スマートフォンのオーディオブランドを読み取る
	scanner.Scan()
	smartphoneBrand := scanner.Text()
	
	// タブレットのモデルを読み取る
	scanner.Scan()
	tabletModel := scanner.Text()
	
	// タブレットのオーディオブランドを読み取る
	scanner.Scan()
	tabletBrand := scanner.Text()
	
	// TODO: 埋め込まれた AudioPlayer を持つ Smartphone を作成する
	
	// TODO: 埋め込まれた AudioPlayer を持つ Tablet を作成する
	
	// TODO: スマートフォンのモデルを出力し、その後スマートフォンで StartPlayback を呼び出す
	
	// TODO: タブレットのモデルを出力し、その後タブレットで StartPlayback を呼び出す
	
	_ = smartphoneModel
	_ = smartphoneBrand
	_ = tabletModel
	_ = tabletBrand
	fmt.Println("TODO: Complete the implementation")
}
quiz icon腕試し

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

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

自分で練習してみよう: Goオンラインコンパイラ