Go言語 errorインターフェース

Goでは、JavaScriptなどの他の言語のようなtry-catchメカニズムはありません。

try {
    // エラー発生
} catch(error) {
    // エラー処理
}

その代わりに、Goはエラーを表現するためのerrorインターフェース型を提供します。エラーインターフェースにはError()メソッドがあり、エラーメッセージを文字列で返します。

type error interface {
    Error() string
}

Goのエラーはこのerror型のインターフェースを使い、値で表現することになっています。 Goにおけるエラー値は下のようにまとめられます。

  • エラーがない場合: nilとして表現
  • エラーが発生した場合: nilではない値として表現

Goでは、errorがnilかどうかを調べることで、エラーを処理することができます。それでは、ファイルの中身を読み込む次のような関数を考えてみましょう。

// ファイルを読み取りその内容を返すと共にerror型の値も返します
func ReadFile() ([]byte, error) {
    // os.Open関数を用いてファイルをオープンし、ファイルディスクリプタとエラー値を返します
    // ファイルが正常にオープンされた場合、エラー値はnilとなります。エラーが発生した場合、エラー値はnilでない値になります
    f, err := os.Open("test.txt")

    // もしerrがnilではない値の場合はファイルの開封に失敗しているので、この関数の実行結果はエラーということになり、発生したエラーを値として返します
    if err != nil {
        return nil, err
    }

    defer f.Close()

    // 同様に、ファイルの内容を読み取る処理も行います
    data, err := io.ReadAll(f)

    if err != nil {
        return nil, err
    }

    // ファイルオープンとファイル内容の読み取りに成功した場合はエラーなしと判断し、この関数のエラーをnilとして返します
    // このようにすることで、この関数の二つ目の返り値であるerrorの値を見ることで、実行結果がエラーなのかエラーでないのかを関数外から判定することができます
    return data, nil
}

関数からエラー値を返すことで、関数の呼び出し側に、エラーが発生したことと、そのエラーメッセージを知らせることができます。

Goでは、関数から返されたエラー値を確認し、そのエラー値に基づいて適切な対処を行うことでエラー処理を行います。try-catch構文に慣れている人には違和感があるかもしれませんが、エラーを単なる値として考えることで、Goでのエラー処理をより自然に感じられるようになります。

Go言語 カスタムエラー

Goでカスタムエラーを作成するには、errorインターフェースのError()メソッドを実装した新しい型を定義するだけです。このメソッドは、エラーを説明する文字列を返す必要があります。

たとえば、ネットワーク接続に失敗した場合のエラータイプを作りたいとします。このような新しい型を定義することができます。

type NetworkError struct {
    message string
}

func (err *NetworkError) Error() string {
    return fmt.Sprintf("Network Error: %s", err.message)
}

この例では、messageというフィールドを1つ持つNetworkErrorという新しい型を定義しています。また、Error()というメソッドを定義し、エラーメッセージの文字列を"Network Error:"というプレフィックス付きで返します。この新しい型を使用して、独自のエラーを作成したり返したりすることができます。

package main

import "fmt"

type NetworkError struct {
    message string
}

func (err *NetworkError) Error() string {
    return fmt.Sprintf("Network Error: %s", err.message)
}

func connect() error {
    return &NetworkError{"Could not connect to server"}
}

func main() {
    err := connect()
    if err != nil {
        fmt.Println(err.Error())
    }
}

この例では、NetworkError型のカスタムエラーを返すconnect関数を作成しました。次にmain関数の中でこの関数を呼び出し、エラーが発生しているかどうかをチェックします。エラーが返された場合は、Error()メソッドを使用してエラーメッセージを出力します。

カスタムエラーは具体的なエラーメッセージをユーザーや開発者に提供するのに便利です。また、エラーの種類を区別して、より具体的な方法でエラーを処理しやすくするためにも使用することができます。

この記事を書いた人

著者の画像

Jeffry Alvarado

Ex-Facebook Engineer 大学ではコンピュータサイエンスを専攻し、在学中に複数のインターンシップを経験。コンピュータサイエンスが学習できるプラットフォームRecursionを創業し、CTOとしてカリキュラム作成、ソフトウェア開発を担当。


ツイート