KDOC 82: errors.Unwrapを読む
この文書のステータス
- 作成
- 2024-02-10 貴島
- レビュー
- 2024-02-12 貴島
コード
https://github.com/kd-collective/go/blob/b8ac61e6e64c92f23d8cf868a92a70d13e20a124/src/errors/wrap.go#L11-L25
// Unwrap returns the result of calling the Unwrap method on err, if err's
// type contains an Unwrap method returning error.
// Otherwise, Unwrap returns nil.
//
// Unwrap only calls a method of the form "Unwrap() error".
// In particular Unwrap does not unwrap errors returned by [Join].
func Unwrap(err error) error {
u, ok := err.(interface {
Unwrap() error
})
if !ok {
return nil
}
return u.Unwrap()
}
引数で渡されたerror型の値が、Unwrap()メソッドを実装してれば実行する。実装してなければnilを返す。それだけ。使ってみる。
import (
"errors"
"testing"
"github.com/stretchr/testify/assert"
)
type wrapped struct {
msg string
err error
}
func (e wrapped) Error() string { return e.msg }
func (e wrapped) Unwrap() error { return e.err }
func TestUnwrap(t *testing.T) {
err1 := errors.New("1")
err2 := wrapped{"wrap 2", err1}
assert.Equal(t, nil, errors.Unwrap(wrapped{"wrapped", nil}))
assert.Equal(t, err1, errors.Unwrap(wrapped{"wrapped", err1}))
assert.Equal(t, err2, errors.Unwrap(wrapped{"wrapped", err2}))
assert.Equal(t, "wrap 2", err2.Error())
assert.Equal(t, "wrap 2", errors.Unwrap(wrapped{"wrapped", err2}).Error())
}
Figure 1: Error()とUnwrap()を使うイメージ
Unwrap() を使うと何がうれしいかというと、エラーの木構造を、 Unwrap() を再帰的に適用してたどれることにある。このため、たとえば「sqlite driverのエラー全般」、という形でグループとしてerrorを扱える。再帰的にたどって一致判定をしているのが errors.Is() と errors.As() である。 Unwrap() 単体だとあまり役に立たない。