Stringer と Error インターフェース
CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 32/107。
Goの標準ライブラリは、頻繁に使用することになる2つのインターフェース、fmt.Stringer と error を定義しています。どちらもシンプルな単一メソッドのインターフェースであり、作成した型にGoの組み込み機能との強力な統合を提供します。
Stringer インターフェースは fmt パッケージで定義されており、メソッドを1つだけ必要とします:
type Stringer interface {
String() string
}独自の型に String() を実装すると、fmt.Println のような関数は自動的にそれを使用して値を表示します。
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}
func main() {
p := Person{Name: "Alice", Age: 30}
fmt.Println(p) // Alice (30歳)
}errorインターフェースも同様にシンプルで、文字列を返すError()メソッドを必要とします:
type error interface {
Error() string
}Error() メソッドを持つ任意の型は、Go においてエラー値として使用できます。これにより、追加のコンテキストを持つカスタムエラー型を作成できます:
type ValidationError struct {
Field string
Message string
}
func (e ValidationError) Error() string {
return fmt.Sprintf("%s: %s", e.Field, e.Message)
}
func main() {
err := ValidationError{Field: "email", Message: "invalid format"}
fmt.Println(err) // email: invalid format
}これらの2つのインターフェースは、暗黙的な実装を通じて強力な振る舞いを引き出す、小さく焦点の絞られたインターフェースというGoの哲学を実証しています。
チャレンジ
簡単Stringer インターフェースと error インターフェースの両方を使用して、読みやすい出力と意味のあるエラーハンドリングを提供する温度監視システムを構築しましょう。
コードは2つのファイルに分けて構成します:
temperature.go:Value(float64) とUnit(string) フィールドを持つTemperature構造体を作成します。出力時に人間が読みやすい形式で温度が表示されるようにString()メソッドを実装してください。また、Temp(float64) とReason(string) フィールドを持つTemperatureError構造体を作成し、説明的なエラーメッセージを提供するError()メソッドを実装してください。main.go:Temperatureを受け取り、温度が無効な場合にエラーを返すValidateTemperatureという関数を作成します。絶対零度(摂氏の場合は -273.15、華氏の場合は -459.67)を下回る場合、温度は無効とみなされます。有効な場合、関数はnilを返します。入力から温度データを読み取り、Temperature を作成し、それを検証して、適切な出力を表示してください。
以下の入力が提供されます:
- 1行目: 温度の値 (float)
- 2行目: 単位 (摂氏の場合は
C、華氏の場合はF)
String() メソッドは以下の形式を返す必要があります:
[Value] degrees [Unit]ここで、Unit は入力に基づいた完全な単語 "Celsius" または "Fahrenheit" です。
Error() メソッドは以下の形式を返す必要があります:
invalid temperature [Temp]: [Reason]温度が有効な場合は、fmt.Println を使用して Temperature を出力します(これにより String() メソッドが使用されます)。無効な場合は、エラーを出力します(これにより Error() メソッドが使用されます)。
例えば、25.5 と C が与えられた場合、出力は以下のようになります:
25.5 degrees Celsius-500 と F が与えられた場合、出力は以下のようになります:
invalid temperature -500: below absolute zero温度が低すぎる場合の理由(reason)には "below absolute zero" を使用してください。
チートシート
Goの標準ライブラリは、2つの重要なインターフェースを定義しています:fmt.Stringerとerrorです。
Stringerインターフェース
fmtパッケージのStringerインターフェースは、1つのメソッドを必要とします:
type Stringer interface {
String() string
}独自の型にString()を実装すると、fmt.Printlnのような関数が自動的にそれを使用します:
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}
func main() {
p := Person{Name: "Alice", Age: 30}
fmt.Println(p) // Alice (30 years old)
}errorインターフェース
errorインターフェースは、文字列を返すError()メソッドを必要とします:
type error interface {
Error() string
}Error()メソッドを持つ任意の型はエラー値として使用でき、追加のコンテキストを持つカスタムエラー型を作成できます:
type ValidationError struct {
Field string
Message string
}
func (e ValidationError) Error() string {
return fmt.Sprintf("%s: %s", e.Field, e.Message)
}
func main() {
err := ValidationError{Field: "email", Message: "invalid format"}
fmt.Println(err) // email: invalid format
}自分で試してみよう
package main
import (
"fmt"
)
// ValidateTemperature は温度が有効かどうかをチェックします
// 温度が絶対零度を下回る場合はエラーを返します
// 絶対零度: 摂氏の場合は -273.15、華氏の場合は -459.67
func ValidateTemperature(t Temperature) error {
// TODO: バリデーションロジックを実装する
// 単位に基づいて温度が絶対零度を下回っていないかチェックする
// 無効な場合は TemperatureError を返し、有効な場合は nil を返す
return nil
}
func main() {
var value float64
var unit string
fmt.Scanln(&value)
fmt.Scanln(&unit)
// TODO: 入力値を使用して Temperature 構造体を作成する
// TODO: ValidateTemperature を使用して温度を検証する
// TODO: エラーがある場合は、エラーを出力する
// そうでない場合は、温度を出力する(String() メソッドが使用されます)
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機4インターフェース
インターフェース入門暗黙的な実装契約としてのインターフェース空のインターフェース (any)型アサーション型スイッチインターフェースの合成Stringer と Error インターフェースまとめ - 図形計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー