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型は、すべてのフィールドを表示する代わりにフォーマット済みの名前を表示したりできます。
チャレンジ
簡単人間にとってわかりやすい形式で時間の長さを表示する、時間追跡システムを作りましょう!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 5mStringerを実装することで、独自の型を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" 形式で出力する
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー11標準ライブラリとOOP
io.Reader と io.Writersort.Interfacefmt.Stringer インターフェースencoding/json と構造体http.Handler インターフェースまとめ:REST API モデル自分で練習してみよう: Goオンラインコンパイラ