ããã¯ããªã«ãããããŠæžãããã®ïŒ
Goã®æ¬ãèªãã ãããµã³ãã«ã³ãŒããèŠãŠããããããšãããããã®ãç®ã«ããã®ã§ããã
file, err = os.Create(filename)
if err == nil {
return
}
nil
ãã©ããã®å€å®ã¯ããŠããâŠã
ãšã©ãŒã®äžèº«ãçš®é¡ã«èžã¿èŸŒã¿ããå Žåã¯ïŒãšããèªåã§ãšã©ãŒãå®çŸ©ããå Žåã¯ïŒããããæ°ã«ãªãã®ã§ã
ã¡ãã£ãšèª¿ã¹ãŠã¿ãããšã«ããŸããã
ã€ã³ãããããããã
ä»åã®ãšã³ããªã®äž»ãªæ
å ±æºã¯ã以äžã§ãã
The Go Programming Language Specification / Errors
Effective Go / 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ãèŠãŠã¿ãŸãã
Effective Go / Errors
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()
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
ãäœæã§ããŸãã
Package fmt / func Errorf
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
æšæºããã±ãŒãžã«å®çŸ©ãããŠãããšã©ãŒã§ç¢ºèªããŠã¿ã
ãŸãã¯ãæšæºããã±ãŒãžã«å®çŸ©ãããŠãããšã©ãŒã§ç¢ºèªããŠã¿ãŸãããã
ç°¡åã«èµ·ããããšã©ãŒã§ãããšæãã€ããã®ãšããŠãéãããšãããã¡ã€ã«ããªãã£ãå Žåãããé¡ã«ããŸãããã
Package os / func Open
ãšã©ãŒãèµ·ãã£ãå Žåã*PathError
ãè¿ã£ãŠããããã§ãã
Package os / type 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
ãèŠããšããããŸãã
Package os / Variables
ä»åã¯ãã¡ã€ã«ãååšããªãã®ã§ãErrNotExist
ãšãªããŸãã
ãªãããããã®ãšã©ãŒã¯syscall
ããã±ãŒãžã®Errno
ãšããåïŒå®äœã¯uintptr
ïŒã§ãã
Package syscall / type Errno
åã®å€å®ã¯ã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:
default:
assert.FailNow(t, "not ENOENT")
}
default:
assert.FailNow(t, "not PathError")
}
}
ãã®éšåã«é¢ããŠã¯ãå€ã§ãæ¯èŒã§ããŸãã
switch err.Err {
case syscall.ENOENT:
default:
assert.FailNow(t, "not ENOENT")
}
次ã«ãããããerrors
ããã±ãŒãžã䜿ã£ãŠæžãæããŠãããŸãããã
errors - The Go Programming Language
As
ãããAs
ã䜿çšãããšããšã©ãŒïŒãšãã®å
éšçã«æã£ãŠããåå ãšãªã£ããšã©ãŒïŒã«å¯ŸããŠæå®ããå€æ°ã®åã«åèŽãããã®ã
ããã°ããã®å€æ°ã«å€ãèšå®ãtrue
ãè¿ããŸããããã§ãªããã°false
ãè¿ããŸãã
Package errors / func As
ãããªæãã§ãããå
ã»ã©ã®*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
ãè¿ããŸãã
Package errors / func Is
èŠããã«ã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
ã
è¿ããŸãã
Package errors / func Unwrap
ãããªæãã§ãã
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ã€æ±ãããšã«ãªã£ãŠãããããããããã£ãã®ã§ããã
æ¹ããŠãšèŠããš
ãšããå®çŸ©ã«ãªã£ãŠããŸããããããã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
ã®å®äœãæã€ãšã©ãŒã«å²ãåœãŠãããæ°åã¯ã以äžã§ç¢ºèªã§ãã
Package syscall / Constants
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
ã䜿ãæ¹æ³ããªããšã
Package errors / func New
Package fmt / func 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ãããããããªãã£ãã®ã§ãæšæºã©ã€ãã©ãªã®äœ¿ãæ¹ãèªåã§ãšã©ãŒãå®çŸ©ããå Žåãå«ããŠã
ããããè©ŠããŠã¿ãŸããã
ããçšåºŠäœ¿ãæ¹ãããã£ãããªïŒãšããæ°ãããŸãã