Menu
Coddy logo textTech

Stringer と Error インターフェース

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

Goの標準ライブラリは、頻繁に使用することになる2つのインターフェース、fmt.Stringererror を定義しています。どちらもシンプルな単一メソッドのインターフェースであり、作成した型に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の哲学を実証しています。

challenge icon

チャレンジ

簡単

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.5C が与えられた場合、出力は以下のようになります:

25.5 degrees Celsius

-500F が与えられた場合、出力は以下のようになります:

invalid temperature -500: below absolute zero

温度が低すぎる場合の理由(reason)には "below absolute zero" を使用してください。

チートシート

Goの標準ライブラリは、2つの重要なインターフェースを定義しています:fmt.Stringererrorです。

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() メソッドが使用されます)
}
quiz icon腕試し

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

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