Menu
Coddy logo textTech

fmt.Stringer インターフェース

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

fmt.Stringerインターフェースは、印刷時に型がどのように表示されるかを制御します。これはGoで最もよく実装されるインターフェースの1つで、fmtパッケージで定義されています。

type Stringer interface {
    String() string
}

fmt.Println%v を使った fmt.Printf、または同様の関数に値を渡すと、Go はその型が Stringer を実装しているか確認します。実装している場合、Go は String() メソッドを呼び出してテキスト表現を取得します。

type Temperature struct {
    Celsius float64
}

func (t Temperature) String() string {
    return fmt.Sprintf("%.1f°C", t.Celsius)
}

func main() {
    temp := Temperature{Celsius: 23.5}
    fmt.Println(temp)  // 23.5°C
}

String() メソッドがない場合、出力にはデフォルトの構造体形式である {23.5} が表示されます。Stringer を実装することで、独自の型をどのように表示するかを正確に制御できます。

これは、フィールドの生の値だけでは意味が明確に伝わらない型に特に役立ちます。Duration型は、生のナノ秒を表示する代わりに「2h 30m」と表示したり、User型は、すべてのフィールドを表示する代わりにフォーマット済みの名前を表示したりできます。

challenge icon

チャレンジ

簡単

人間にとってわかりやすい形式で時間の長さを表示する、時間追跡システムを作りましょう!fmt.Stringerインターフェースを実装して、カスタム型が印刷時にどのように表示されるかを制御します。

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

  • duration.go:カスタム文字列表現を持つ、時間関連の型を定義します。

    合計分数を整数として格納するDuration構造体を作成します。String()メソッドを実装し、印刷時に、150分の場合は2h 30m、45分の場合は0h 45mのような読みやすい形式で表示されるようにします。時間と分は常に表示する必要があります。

    Name(string)とTime(Duration)フィールドを持つTask構造体を作成します。TaskにString()を実装し、[Name]: [duration]の形式で表示します。このとき、時間の長さには独自のStringメソッドを使用します。

  • main.go:時間の長さとともにタスクを作成して表示します。

    タスクの数を読み取り、各タスクについて名前と分単位の時間の長さを読み取ります。Taskインスタンスを作成し、それぞれをfmt.Printlnで直接印刷します。Stringerインターフェースが自動的に書式設定を処理します。

    すべてのタスクを印刷した後、すべてのタスクの合計時間を計算し、次の形式で印刷します。

    Total: [duration]

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

  • 1行目:タスクの数
  • 続く行:タスク名と分数(タスクごとに2行)

たとえば、次の入力が与えられた場合:

3
Code Review
90
Meeting
45
Documentation
120

出力は次のようになります。

Code Review: 1h 30m
Meeting: 0h 45m
Documentation: 2h 0m
Total: 4h 15m

また、次の入力が与えられた場合:

2
Design
180
Testing
65

出力は次のようになります。

Design: 3h 0m
Testing: 1h 5m
Total: 4h 5m

Stringerを実装することで、独自の型をGoの印刷関数とシームレスに統合できます。{90}のような構造体のフィールドがそのまま表示される代わりに、ユーザーにとって意味のある、わかりやすい出力を得られます。

自分で試してみよう

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// タスク数を読み取る
	line, _ := reader.ReadString('\n')
	numTasks, _ := strconv.Atoi(strings.TrimSpace(line))

	// TODO: タスクを格納するスライスを作成する
	// TODO: 合計分数を追跡する

	for i := 0; i < numTasks; i++ {
		// タスク名を読み取る
		name, _ := reader.ReadString('\n')
		name = strings.TrimSpace(name)

		// タスクの所要時間(分)を読み取る
		minutesLine, _ := reader.ReadString('\n')
		minutes, _ := strconv.Atoi(strings.TrimSpace(minutesLine))

		// TODO: nameとDurationでTaskを作成する
		// TODO: タスクを出力する(fmt.PrintlnはStringerインターフェースを使用する)
		// TODO: 分数を合計に加算する
		_ = name
		_ = minutes
	}

	// TODO: 合計時間を "Total: Xh Ym" 形式で出力する
}
quiz icon腕試し

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

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

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