🔍

Go1.23以降でのerrors.Is:ネスト不要でエラーハンドリングをシンプルに

に公開

Goのエラーハンドリングにおける errors.Is の変化について、特にバージョン1.22から1.23への移行で注目すべきポイントがあります。この記事では、その違いと、コードのリファクタリング方法について説明します。💡

変更点: errors.Is の挙動の違い 🧐

Go 1.23以降では、 errors.Is の内部に nil チェックが含まれるようになりました。これにより、以下のように err != nil を明示的にチェックするコードがよく見られますが…

if err != nil {
    if errors.Is(err, targetErr) {
        // targetErr に一致した処理
    }
}

実はこれ、Go 1.23以降ではネストしなくても同じ結果が得られるようになりました。具体的には、 errors.Is 内で nil のチェックが行われるので、次のように書くことが可能です。

if errors.Is(err, targetErr) {
    // targetErr に一致した処理
}
if err != nil {
    // その他の処理
}

なぜこれが効率的なのか?⚡

Go 1.23以降、 errors.Is 内で nil のチェックが自動で行われるため、重複して err != nil のチェックを行う必要がなくなりました。これにより、コードがシンプルで読みやすくなります。

実際の動作を確認してみよう!📝

次に、簡単なコードでこの動作を確認しましょう。

コード例 1: Go 1.22 のスタイル

package main

import (
    "errors"
    "fmt"
)

var targetErr = errors.New("target error")

func checkError(err error) {
    if err != nil {
        if errors.Is(err, targetErr) {
            fmt.Println("Matched target error!")
        } else {
            fmt.Println("Different error")
        }
    } else {
        fmt.Println("No error occurred.")
    }
}

func main() {
    err := fmt.Errorf("wrapped: %w", targetErr)
    checkError(err)
}

コード例 2: Go 1.23 以降のスタイル

package main

import (
    "errors"
    "fmt"
)

var targetErr = errors.New("target error")

func checkError(err error) {
    if errors.Is(err, targetErr) {
        fmt.Println("Matched target error!")
    } else if err != nil {
        fmt.Println("Different error")
    } else {
        fmt.Println("No error occurred.")
    }
}

func main() {
    err := fmt.Errorf("wrapped: %w", targetErr)
    checkError(err)
}

結論 💡

Go 1.23以降では、 errors.Is が内部で nil チェックを行うため、無駄なネストを避けてスッキリしたコードを書けるようになりました。コードの可読性とシンプルさは、プロジェクトのメンテナンス性を向上させる重要な要素です。ぜひ、 if err != nil を省略する書き方を検討してみてください!

それでは、シンプルなコードライフをお楽しみください!😄


参考ブログ記事:Go errors.Is now includes a nil check.

Discussion