ããã¯ããªã«ãããããŠæžãããã®ïŒ
Goã®æ¬ãèªãã ãããµã³ãã«ã³ãŒããèŠãŠããããããšãããããã®ãç®ã«ããã®ã§ããã
file, err = os.Create(filename) if err == nil { return }
nil
ãã©ããã®å€å®ã¯ããŠããâŠã
ãšã©ãŒã®äžèº«ãçš®é¡ã«èžã¿èŸŒã¿ããå Žåã¯ïŒãšããèªåã§ãšã©ãŒãå®çŸ©ããå Žåã¯ïŒããããæ°ã«ãªãã®ã§ã
ã¡ãã£ãšèª¿ã¹ãŠã¿ãããšã«ããŸããã
ã€ã³ãããããããã
ä»åã®ãšã³ããªã®äž»ãªæ å ±æºã¯ã以äžã§ãã
The Go Programming Language Specification / Errors
errors - The Go Programming Language
Working with Errors in Go 1.13 - The Go Blog
èšèªä»æ§ãEffective Goããããã®ãšã©ãŒã®ã»ã¯ã·ã§ã³ãerrors
ããã±ãŒãžãããããGo 1.13以éã®ãšã©ãŒãæ±ãããšã«
ã€ããŠã®ããã°ã§ãã
ãã®ããããèŠãããå®éã«åãããŠã¿ãŠããããèããã®ã§ããããããªæãã§ããããïŒ
- èªåã§ãšã©ãŒãäœããäœããªãã«é¢ä¿ãªã
- ãšã©ãŒã«é¢ããæ¡ä»¶å€å®ã«ã¯
erros.Is
ã䜿ã - å
·äœçãªãšã©ãŒã®åã®å€æ°ã«æçžããéã«ã¯ã
erros.As
ã䜿ã
- ãšã©ãŒã«é¢ããæ¡ä»¶å€å®ã«ã¯
- èªåã§ãšã©ãŒãäœãå Žå
erros.New
ããå§ãã- ä»ã®ãšã©ãŒãåå ãšãããç°¡åãªãšã©ãŒãäœæããå Žåã¯
fmt.Errorf
ãš%w
æžåŒã䜿ã - ãšã©ãŒã®å
容ãåºå®ã§ããå Žåã¯ã
Err
ã§å§ãŸãååã§ããã±ãŒãžãããšã¯ã¹ããŒãããŠããïŒâ»1ïŒ - é¢æ°åŒã³åºãæã«ãšã©ãŒã®ã€ã³ã¹ã¿ã³ã¹ãäœæããå Žåã¯ã
error.Is
ã§æ¯èŒå¯èœãªæ段ãæäŸããŠããïŒâ»2ïŒ- VariableãšçŽæ¥æ¯èŒã§ããªããã
- ãšã©ãŒã®çºçåå çãæ¯èŒå¯èœãªæ
å ±ã䜿ã£ãŠ
error.Is
ãããããšã«ãªãïŒ
- èªåã§ãšã©ãŒã«é¢ããæ§é äœãå®çŸ©ããå Žåã¯ã
Error
ãå°ãªããšãUnwrap
ã¡ãœãããäœæãã- åã®ååã¯
Error
ã§çµããããã«ãã - æ¯èŒãã«ã¹ã¿ãã€ãºããå Žåã¯
Is
ãAs
ã®äœæãèãã
- åã®ååã¯
GoãèŠãŠããæããâ»1ã®å Žåã¯éåžžã®åãšããŠãâ»2ã®å Žåã¯ãšã©ãŒã®åããã€ã³ã¿ãšããããšã«ãªãã®ããªïŒãšãã
å°è±¡ãæã¡ãŸããã
ãšã©ãŒãšã¯ïŒ
Goã®èšèªä»æ§ã«é¢ããå 容ãèŠãŠã¿ãŸãã
The Go Programming Language Specification / Errors
Goã§ãããšã©ãŒãšã¯ã以äžã®ããã«å®çŸ©ãããerror
ã€ã³ã¿ãŒãã§ãŒã¹ã§ããèŠããã«ãstring
ãè¿ãError
ã¡ãœããã
å®è£
ããªããããšã
type error interface { Error() string }
Goã§äœ¿ãå€æ°ã®é¢æ°ã®ãã¡ããšã©ãŒãçºçããå¯èœæ§ããããã®ã¯ãæåããæã®å€ãšerror
ã®ã€ã³ã¹ã¿ã³ã¹ãè¿ããããª
è€æ°ã®æ»ãå€ãè¿ããå®çŸ©ã«ãªã£ãŠããŸãã
error
ãè¿ããå®çŸ©ã«ãªã£ãŠããé¢æ°ã®æ»ãå€ã¯ãå
ã«è¿ãããerror
ãnil
ãã©ããã確èªãããšããããã¹ã¿ãŒãããšãªããŸãã
ããã§ãEffective GoãèŠãŠã¿ãŸãã
error
ãnil
ã§ãªãå Žåã§ãããã«ãšã©ãŒã®äžèº«ã«èžã¿èŸŒãå ŽåïŒèµ·ãã£ãäºè±¡ãåå ãç¥ãããå Žåãªã©ïŒã¯ã
åã¢ãµãŒã·ã§ã³ã䜿ã£ãŠå
·äœçãªåã®å€æ°ã«ä»£å
¥ããŠãã£ãŒã«ããèŠããããŸãã
for try := 0; try < 2; try++ { file, err = os.Create(filename) if err == nil { return } if e, ok := err.(*os.PathError); ok && e.Err == syscall.ENOSPC { deleteTempFiles() // Recover some space. continue } return }
ãããããŸãã¯åºæ¬ïŒïŒïŒã¿ããã§ããã
errorsããã±ãŒãžãšfmtããã±ãŒãž
次ã«ãerrors
ããã±ãŒãžãèŠãŠã¿ãŸãã
errors - The Go Programming Language
erros
ããã±ãŒãžã«ã¯ãerror
ãæ±ãé¢æ°ãå«ãŸããŠããŸãã
- æååïŒã¡ãã»ãŒãžïŒãã
error
ãäœæããNew
error
ã«å¥ã®error
ãå«ãŸããå ŽåããããåãåºãUnwrap
error
ãïŒUnwrap
ããããšãå«ããŠïŒç¹å®ã®error
ãšæ¯èŒããIs
error
ãïŒUnwrap
ããŠããïŒç¹å®ã®åã®åŒæ°ã«å²ãåœãŠãAs
https://github.com/golang/go/blob/go1.15.6/src/errors/errors.go
https://github.com/golang/go/blob/go1.15.6/src/errors/wrap.go
ãŸããfmt
ããã±ãŒãžã®Errorf
é¢æ°ã䜿ãããšã§ãerror
ãäœæã§ããŸãã
Errorf
é¢æ°ã¯æå®ããæååãšãã®äžã«å«ãŸããæžåŒããerror
ãäœæããŸããããã®æã«%w
æžåŒãšãã®åŒæ°ãšããŠerror
ã
å«ããããšã«ãããerrors.Unwrap
ããããšãã§ããerror
ïŒåå ãšãªãerror
ãå«ãã error
ãäœæããŸãã
https://github.com/golang/go/blob/go1.15.6/src/fmt/errors.go
ãšã©ãŒã®åå ãå«ããªãå Žåã¯ãfmt.Errorf
ã¯errors.New
ãšå®å
šã«åçã§ãã
ã§ã¯ããã®ãããã®APIã䜿ã£ãŠã¡ãã£ãšç¢ºèªããŠãã£ãŠã¿ãŸãããã
ç°å¢
ä»åã®ç°å¢ã¯ããã¡ãã
$ go version go version go1.15.6 linux/amd64
ã¢ãžã¥ãŒã«äœæã
$ go mod init error-handling go: creating new go.mod: module error-handling
確èªã¯ããã¹ãã³ãŒãã§è¡ããŸãã
go.mod
module error-handling go 1.15 require github.com/stretchr/testify v1.7.0
æšæºããã±ãŒãžã«å®çŸ©ãããŠãããšã©ãŒã§ç¢ºèªããŠã¿ã
ãŸãã¯ãæšæºããã±ãŒãžã«å®çŸ©ãããŠãããšã©ãŒã§ç¢ºèªããŠã¿ãŸãããã
ç°¡åã«èµ·ããããšã©ãŒã§ãããšæãã€ããã®ãšããŠãéãããšãããã¡ã€ã«ããªãã£ãå Žåãããé¡ã«ããŸãããã
ãšã©ãŒãèµ·ãã£ãå Žåã*PathError
ãè¿ã£ãŠããããã§ãã
ãã¹ãã³ãŒãã®é圢ãçšæã
file_read_error_test.go
package main import ( "errors" "github.com/stretchr/testify/assert" "os" "syscall" "testing" ) // ããã«ããã¹ããæžãïŒ
æåã¯ã·ã³ãã«ã«ãè¿ã£ãŠããerror
ãnil
ãã©ããã ã確èªã
func TestOpenFileSuccess(t *testing.T) { file, err := os.Open("file_read_error_test.go") if err == nil { assert.Equal(t, "file_read_error_test.go", file.Name()) } else { assert.Failf(t, "can't open file", "target file = %s", "file_read_error_test.go") } }
ãããããããªã³ãŒãã§ãã
次ã«ãåã¢ãµãŒã·ã§ã³ã䜿ã£ãŠ*PathError
ãšããŠæ±ã£ãŠã¿ãŸãã
The Go Programming Language Specification / Type assertions
func TestOpenFileFailureTypeAssertion1(t *testing.T) { _, err := os.Open("not_found_file") if err == nil { assert.FailNow(t, "file exists") } if pathError, isPathError := err.(*os.PathError); isPathError { assert.Equal(t, "open", pathError.Op) assert.Equal(t, "not_found_file", pathError.Path) assert.Equal(t, "no such file or directory", pathError.Err.Error()) assert.Equal(t, syscall.ENOENT, pathError.Err) errno, isErrno := pathError.Err.(syscall.Errno) assert.True(t, isErrno) assert.True(t, errno.Is(os.ErrNotExist)) } else { assert.FailNow(t, "not PathError") } }
*PathError
åã«ã§ããŠããŸãã°ãããã€ããã£ãŒã«ããããã®ã§ããå°ã詳现ãªå
容ã確èªã§ããŸãã
assert.Equal(t, "open", pathError.Op) assert.Equal(t, "not_found_file", pathError.Path) assert.Equal(t, "no such file or directory", pathError.Err.Error())
ãŸã*PathError
ã¯Err
ãšãããã£ãŒã«ãã«ãšã©ãŒã®çºçåå ãæã£ãŠããŠããã¡ãã§os
ããã±ãŒãžã䜿ã£ãŠãšã©ãŒã®çš®é¡ã
確èªã§ããŸãã
assert.Equal(t, syscall.ENOENT, pathError.Err) errno, isErrno := pathError.Err.(syscall.Errno) assert.True(t, isErrno) assert.True(t, errno.Is(os.ErrNotExist))
os
ããã±ãŒãžã«å®çŸ©ãããŠãããšã©ãŒã¯ãVariables
ãèŠããšããããŸãã
ä»åã¯ãã¡ã€ã«ãååšããªãã®ã§ãErrNotExist
ãšãªããŸãã
ãªãããããã®ãšã©ãŒã¯syscall
ããã±ãŒãžã®Errno
ãšããåïŒå®äœã¯uintptr
ïŒã§ãã
åã®å€å®ã¯ãType switchesã䜿ãæ¹æ³ãããã§ãããã
The Go Programming Language Specification / Type switches
func TestOpenFileFailureTypeAssertion2(t *testing.T) { _, err := os.Open("not_found_file") if err == nil { assert.FailNow(t, "file exists") } switch err := err.(type) { case *os.PathError: assert.Equal(t, "open", err.Op) assert.Equal(t, "not_found_file", err.Path) assert.Equal(t, "no such file or directory", err.Err.Error()) assert.Equal(t, syscall.ENOENT, err.Err) switch errno := err.Err.(type) { case syscall.Errno: assert.True(t, errno.Is(os.ErrNotExist)) default: assert.FailNow(t, "not Errno") } switch err.Err { case syscall.ENOENT: // no-op default: assert.FailNow(t, "not ENOENT") } default: assert.FailNow(t, "not PathError") } }
ãã®éšåã«é¢ããŠã¯ãå€ã§ãæ¯èŒã§ããŸãã
switch err.Err { case syscall.ENOENT: // no-op default: assert.FailNow(t, "not ENOENT") }
次ã«ãããããerrors
ããã±ãŒãžã䜿ã£ãŠæžãæããŠãããŸãããã
errors - The Go Programming Language
As
ãããAs
ã䜿çšãããšããšã©ãŒïŒãšãã®å
éšçã«æã£ãŠããåå ãšãªã£ããšã©ãŒïŒã«å¯ŸããŠæå®ããå€æ°ã®åã«åèŽãããã®ã
ããã°ããã®å€æ°ã«å€ãèšå®ãtrue
ãè¿ããŸããããã§ãªããã°false
ãè¿ããŸãã
ãããªæãã§ãããå
ã»ã©ã®*PathError
ã«å¯Ÿããåã¢ãµãŒã·ã§ã³ãæžãæãããã®ã§ãã
func TestOpenFileFailureUsingErrorsAs1(t *testing.T) { _, err := os.Open("not_found_file") if err == nil { assert.FailNow(t, "file exists") } var pathError *os.PathError if errors.As(err, &pathError) { assert.Equal(t, "open", pathError.Op) assert.Equal(t, "not_found_file", pathError.Path) assert.Equal(t, "no such file or directory", pathError.Err.Error()) assert.Equal(t, syscall.ENOENT, pathError.Err) var errno syscall.Errno if errors.As(err, &errno) { assert.True(t, errno.Is(os.ErrNotExist)) } else { assert.FailNow(t, "not Errno") } } else { assert.FailNow(t, "not PathError") } }
å
éšçã«æã£ãŠãããšã©ãŒâŠãã§ã€ã³ããããšã©ãŒã«å¯ŸããŠãèŠãããšãã話ãªã®ã§ã*PathError
ãããããªãsyscall.Errno
ãŸã§
åŒãæãããšãå¯èœã§ãã
func TestOpenFileFailureUsingErrorsAs2(t *testing.T) { _, err := os.Open("not_found_file") if err == nil { assert.FailNow(t, "file exists") } var errno syscall.Errno if errors.As(err, &errno) { assert.True(t, errno.Is(os.ErrNotExist)) } else { assert.FailNow(t, "not Errno") } }
次ã¯ãIs
ã§ããIs
ã䜿ããšããšã©ãŒïŒãšãã®å
éšçã«æã£ãŠããåå ãšãªã£ããšã©ãŒïŒã«å¯ŸããŠãåŒæ°ã§æå®ããerror
ã«
åèŽãããã®ãããã°ãtrue
ãè¿ããŸããããã§ãªããã°false
ãè¿ããŸãã
èŠããã«ãAs
ã§å€æ°ã«å€ãæçžããªãçã¿ãããªãã®ã§ãã
ã·ã³ãã«ã«ãæ¡ä»¶åå²ã§äœ¿ãã®ã§ãããã
func TestOpenFileFailureUsingErrorsIs(t *testing.T) { _, err := os.Open("not_found_file") if err == nil { assert.FailNow(t, "file exists") } if errors.Is(err, os.ErrNotExist) { pathError, _ := err.(*os.PathError) assert.Equal(t, "no such file or directory", pathError.Err.Error()) } else { assert.FailNow(t, "not PathError") } }
*PathError
ã®å Žåãå€ãšããŠæ¯èŒããerror
ããªãã®ã§os.ErrNotExist
ã§æ¯èŒããŸãããããã§true
ã«ãªããŸãã
if errors.Is(err, os.ErrNotExist) {
æåŸã¯Unwrap
ã§ããUnwrap
ã䜿ããšãæå®ããerror
ãUnwrap
ã¡ãœãããå®è£
ããŠããå ŽåãUnwrap
ã¡ãœããã®
åŒã³åºãçµæãè¿ããŸããèŠããã«ãerror
ã®åå ãè¿ããŸããUnwrap
ã¡ãœãããå®è£
ããŠããªãã£ãå Žåã¯ãnil
ã
è¿ããŸãã
ãããªæãã§ãã
func TestOpenFileFailureUsingErrorsUnwrap(t *testing.T) { _, err := os.Open("not_found_file") if err == nil { assert.FailNow(t, "file exists") } unwrapped := errors.Unwrap(err) if errno, isErrno := unwrapped.(syscall.Errno); isErrno { assert.True(t, errno.Is(os.ErrNotExist)) } else { assert.FailNow(t, "not PathError") } }
ãã¡ã€ã«æªååšã®å Žåã®*PathError
åã®å€æ°ãerrors.Unwrap
ã«æž¡ããšããã®åå ïŒsyscall.Errno
ïŒãååŸã§ããŸãã
errors
ããã±ãŒãžã®äœ¿ãæ¹ã¯ãããªæãã§ãã
ãšããã§ãä»åã®ãé¡ã§ã¯*PathError
ãsyscall.Errno
ãos.ErrNotExist
ãš3ã€æ±ãããšã«ãªã£ãŠãããããããããã£ãã®ã§ããã
æ¹ããŠãšèŠããš
- Package os / type PathError âŠ
Error
ãUnwrap
ïŒãšTimeout
ïŒã¡ãœãããå®è£ ããæ§é äœ - Package syscall / type Errno âŠ
Error
ãUnwrap
ïŒãšTemporary
ãTimeout
ïŒã¡ãœãããå®è£ ããuintptr
- Package os / VariablesïŒ
os.ErrNotExist
ïŒ âŠerrors.New
ã§äœæãããerror
ïŒå€æ°ïŒ
ãšããå®çŸ©ã«ãªã£ãŠããŸãããããããerror
ã€ã³ã¿ãŒãã§ãŒã¹ã®å®çŸ©ãæºãããŠããŸãã
*PathError
ã¯Err
ãã£ãŒã«ããUnwrap
ã§è¿ãããã«ãªã£ãŠããããšããã
https://github.com/golang/go/blob/go1.15.6/src/os/error.go#L58
*PathError
â åå â syscall.Errno
â å®äœã®å or åå â os.ErrNotExist
ã¿ãããªé¢ä¿ã«ãªã£ãŠããã®ããªãšæã£ãã®ã§ããã
ããã§ã¯ãªããsyscall.Errno
ã¯Is
ã§åãåã£ãerror
ã®å€ã䜿ã£ãæ¯èŒåŠçãè¡ã£ãŠããã®ã§
https://github.com/golang/go/blob/go1.15.6/src/syscall/syscall_unix.go#L126-L136
*PathError
ãUnwrap
ããçµæã==
ã§çŽæ¥os.ErrNotExist
ãšæ¯èŒããŠãtrue
ã«ãªããã«ãã ãã¶æ··ä¹±ããŸããã
errors.Is
ã§æ¯èŒãããšãtrue
ã«ãªãã®ã«âŠãšã
Is
ã®äœ¿ãæ¹ãã¡ãããšèŠãæãã§ããâŠã
ãŸããErrno
ã®å®äœãæã€ãšã©ãŒã«å²ãåœãŠãããæ°åã¯ã以äžã§ç¢ºèªã§ãã
https://github.com/golang/go/blob/go1.15.6/src/syscall/tables_js.go#L102-L228
os.Errã
ã«å²ãåœãŠãããå®äœã¯ããã¡ããèŠããšç¢ºèªã§ããŸãã
https://github.com/golang/go/blob/go1.15.6/src/os/error.go#L29-L34
ã ãã¶ãåã«æ¯ãåãããŸãããâŠã
èªåã§ãšã©ãŒãå®çŸ©ãã
ãããŸã§ã¯ãæšæºããã±ãŒãžã«å®çŸ©ãããŠãããšã©ãŒã䜿ããŸããããããããã¯èªåã§ãšã©ãŒãå®çŸ©ããŠãããŸãããã
ã³ãŒãã®é圢ãæžããŠãããŸãã
ãšã©ãŒãå®çŸ©ããæ¹ã
myerrors.go
package main import ( "errors" ) // ããã«ããšã©ãŒãå®çŸ©ããŠãã
ãã¹ãã³ãŒããæžãæ¹ã
myerrors_test.go
package main import ( "errors" "fmt" "github.com/stretchr/testify/assert" "os" "syscall" "testing" ) // ããã«ããã¹ããæžãïŒ
èªåã§ãšã©ãŒãå®çŸ©ãã1çªã·ã³ãã«ãªãã¿ãŒã³ãšããŠã¯ãerrors.New
ãfmt.Errorf
ã䜿ãæ¹æ³ããªããšã
errors.New
ã¯æååããerror
ãäœæããfmt.Errorf
ã¯æžåŒã䜿ãã€ã€æååããerror
ãäœæããŸãã
ãã¹ãã³ãŒãã§å®çŸ©ãããšããããªæãã«ã
func TestCreateError(t *testing.T) { error1 := errors.New("Oops!!") assert.Error(t, error1) assert.Equal(t, "Oops!!", error1.Error()) assert.Nil(t, errors.Unwrap(error1)) error2 := fmt.Errorf("Oops!!") assert.Error(t, error2) assert.Equal(t, "Oops!!", error2.Error()) assert.Nil(t, errors.Unwrap(error2)) }
ã©ã¡ããError
ã¡ãœãããå®è£
ããŠããŸãããã®å Žåã¯ãerrors.Unwrap
ãåŒã³åºããŠãåæ¹nil
ã§ãã
ãã ãfmt.Errorf
ã®å ŽåãæžåŒã«%w
ãå«ããããã«error
ãããŠã¯ãããšUnwrap
ã§æå®ããerror
ãè¿ãããã«æ§ç¯ãããŸãã
ãããªæãã§ããã
func TestWrapedError1(t *testing.T) { _, err := os.Open("not_found_file") wrappedError := fmt.Errorf("Open file error, reason [%w]", err) assert.Error(t, wrappedError) assert.Equal(t, "Open file error, reason [open not_found_file: no such file or directory]", wrappedError.Error()) assert.Equal(t, "*fmt.wrapError", fmt.Sprintf("%T", wrappedError)) causeError := errors.Unwrap(wrappedError) assert.True(t, err == causeError) assert.True(t, errors.Is(wrappedError, os.ErrNotExist)) assert.ErrorIs(t, wrappedError, os.ErrNotExist) }
ãã¡ã€ã«æªååšã®ãšã©ãŒãå
ã«ããŠ%w
ã«äžã
_, err := os.Open("not_found_file") wrappedError := fmt.Errorf("Open file error, reason [%w]", err)
ãããUnwrap
ãããš%w
ã«æå®ãããã®ãšåãã§ããããšã確èªã§ããŸãã
causeError := errors.Unwrap(wrappedError) assert.True(t, err == causeError)
ããŸãæå³ã¯ãªãã§ããã%w
ã ããäžããŠUnwrap
ã§è¿ãããããšãã§ããŸãã
func TestWrapedError2(t *testing.T) { _, err := os.Open("not_found_file") wrappedError := fmt.Errorf("%w", err) assert.Error(t, wrappedError) assert.Equal(t, "open not_found_file: no such file or directory", wrappedError.Error()) assert.Equal(t, "*fmt.wrapError", fmt.Sprintf("%T", wrappedError)) causeError := errors.Unwrap(wrappedError) assert.True(t, err == causeError) assert.True(t, errors.Is(wrappedError, os.ErrNotExist)) assert.ErrorIs(t, wrappedError, os.ErrNotExist) }
myerrors.go
åŽã«ãVariableãšããŠerror
ãå®çŸ©ïŒãšã¯ã¹ããŒãïŒããé¢æ°åŒã³åºãã®çµæãšããŠerror
ãè¿ãããã«ããŠã¿ãŸãããã
var ( ErrMySimpleError = errors.New("My Error") ) func GetMySimpleErr() error { return ErrMySimpleError }
VariableãšããŠãšã¯ã¹ããŒãããerror
ã®ååã¯ãErr
ã§å§ããã®ãéäŸã®ããã§ãã
ãã¹ãã³ãŒãã¯ãããªæãã§ã
func TestGetMySimpleErr(t *testing.T) { err := GetMySimpleErr() assert.Equal(t, ErrMySimpleError, err) assert.Equal(t, "My Error", err.Error()) assert.Equal(t, "*errors.errorString", fmt.Sprintf("%T", err)) }
æåŸã«ããšã©ãŒãæ§é äœã§å®çŸ©ããŠã¿ãŸãã
2ã€çšæããŠãçæ¹ã¯ãšã©ãŒã®åå ãæãŠãããã«ããŸããããšããã§ããšã©ãŒãšãªãåã®ååã¯Error
ã§çµããããã®ãéäŸã®
ããã§ãã1ãšã2ãšãä»ããŠããŸããŸããâŠã
type MyError1 struct { Message string } func (e MyError1) Error() string { return e.Message } func (e MyError1) Is(target error) bool { return errors.Is(e, target) } type MyError2 struct { Message string Cause error } func (e *MyError2) Error() string { return e.Message + ": " + e.Cause.Error() } func (e *MyError2) Unwrap() error { return e.Cause }
Error
ã¡ãœãããå®è£
ããã®ã¯error
ãšããŠã®å¿
é æ¡ä»¶ã§ãããMyError1
ã®æ¹ã¯Is
ããMyError2
ã®æ¹ã¯Unwrap
ãå®è£
ããŠ
ãããŸããã
MyError1
ã®æ¹ã¯ãVariableãšããŠåºå®ã§å®çŸ©ããŸãã
var ( ErrMyError = MyError1{Message: "Oops!!"} )
MyError2
ã®æ¹ã¯ãå®è¡æã«ãšã©ãŒã®åå ãå«ãã§åçã«äœæããããšã«ããŸãã
ããã2ã€ã®ãšã©ãŒããåŒæ°ã®æå®ã§ã©ã¡ããã®ãšã©ãŒïŒãããã¯æ£åžžã«å€ãè¿ãïŒãè¿ããããªé¢æ°ãäœæããŸãã
func Execute(word string, cause error) (string, error) { switch word { case "Error1": return "NG", ErrMyError case "Error2": e := &MyError2{Message: "Oops!!", Cause: cause} return "NG", e default: return "OK", nil } }
MyError2
ã®æ¹ã¯ããã®é¢æ°åŒã³åºãæã«æ§é äœã®ã€ã³ã¹ã¿ã³ã¹ãäœæããŠããŸããããã€ã³ã¿ãè¿ãããã«ããŸããã
*PathError
ãšåãã§ããã
https://github.com/golang/go/blob/go1.15.6/src/os/file_unix.go#L210
ä»ã®ããã±ãŒãžãããã€ãèŠãã®ã§ãããé¢æ°ã®åŒã³åºãæã«ãšã©ãŒçºçæã®æ
å ±ãå«ãããªã©ã®çç±ã§ã€ã³ã¹ã¿ã³ã¹ãäœã£ããã®ã¯ã
ãã€ã³ã¿ãè¿ããŠããããã«æããŸããããã«ç¿ããŸããã
ãã¹ãã³ãŒãã§ç¢ºèªããŠã¿ãŸãã
MyError1
ã®ç¢ºèªã
func TestMyCustomError1(t *testing.T) { _, err := os.Open("not_found_file") result, myerr := Execute("Error1", err) assert.Equal(t, "NG", result) assert.True(t, myerr == ErrMyError) assert.Equal(t, "Oops!!", myerr.Error()) assert.True(t, errors.Is(myerr, ErrMyError)) assert.Nil(t, errors.Unwrap(myerr)) var e MyError1 assert.True(t, errors.As(myerr, &e)) }
é¢æ°ã®æ»ãå€ãšãªã£ãerror
ãã==
ãerrors.Is
ã§æ¯èŒã§ããŸãã
assert.True(t, myerr == ErrMyError) assert.True(t, errors.Is(myerr, ErrMyError))
Unwrap
ã¯å®è£
ããŠããªãã®ã§nil
ã§ããã
assert.Nil(t, errors.Unwrap(myerr))
errors.As
ã§å€æ°ã«æçžãã§ããŸãã
var e MyError1
assert.True(t, errors.As(myerr, &e))
ç¶ããŠãMyError2
ã䜿ãæ¹ã
func TestMyCustomError2(t *testing.T) { _, err := os.Open("not_found_file") _, myerr := Execute("Error2", err) assert.Equal(t, "Oops!!: open not_found_file: no such file or directory", myerr.Error()) assert.True(t, errors.Is(myerr, os.ErrNotExist)) assert.True(t, errors.Unwrap(myerr) == err) var e *MyError2 assert.True(t, errors.As(myerr, &e)) var errno syscall.Errno assert.True(t, errors.As(myerr, &errno)) }
Is
ã¡ãœããã¯å®è£
ããŠããªãã®ã§ãããæ®éã«äœ¿ããŸãã
assert.True(t, errors.Is(myerr, os.ErrNotExist))
Unwrap
ã¡ãœãããå®è£
ããŠããã°ããã¡ããèŠãŠãããã®ã§ã
https://github.com/golang/go/blob/go1.15.6/src/errors/wrap.go#L39-L59
åçŽæ¯èŒãIs
ãUnwrap
ãšæšç§»ããŠããã®ã§ãæ¯èŒã«ç¹æ®ãªæ¡ä»¶ããªããã°Unwrap
ãå®è£
ããŠããã®ãããã®ã§ãããã
errors.Unwrap
ã§ã¯ããšã©ãŒã®åå ãååŸã§ããŸããããã¯ãUnwrap
ã¡ãœãããå®è£
ããããã§ããã
assert.True(t, errors.Unwrap(myerr) == err)
errors.As
ã§ã®å€æ°ãžã®æçžã
var e *MyError2
assert.True(t, errors.As(myerr, &e))
ãã¡ãããAs
ã¡ãœãããå®è£
ããŠããªããŠãUnwrap
ã¡ãœããã®åŒã³åºãçµæã䜿ã£ãŠãããŸãã
https://github.com/golang/go/blob/go1.15.6/src/errors/wrap.go#L77-L101
*PathError
ã®æãšåãããã«ãerrors
Asã§äžæ°ã«
syscall.Errno`ãååŸããããšãã§ããŸãã
var errno syscall.Errno
assert.True(t, errors.As(myerr, &errno))
ãããªæãã§ããããã
ãŸãšã
Goã®ãšã©ãŒã«é¢ããAPIãããããããªãã£ãã®ã§ãæšæºã©ã€ãã©ãªã®äœ¿ãæ¹ãèªåã§ãšã©ãŒãå®çŸ©ããå Žåãå«ããŠã
ããããè©ŠããŠã¿ãŸããã
ããçšåºŠäœ¿ãæ¹ãããã£ãããªïŒãšããæ°ãããŸãã