// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
type error interface {
Error() string
}
Tip 任何实现error接口的都是error类型
1. Converting the error to the underlying type and retrieving more information from the struct fields
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Open("/test.txt")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(f.Name(), "opened successfully")
}
type PathError struct {
Op string
Path string
Err error
}
func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }
We can use the As function from errors package to convert the error to its underlying type.
The As function’s description talks about error chain. Please ignore it for now. We will understand how error chain and wrapping works in a separate tutorial.
A simple description of As is that it tries to convert the error to a error type and returns either true or false indicating whether the conversion is successful or not.
package main
import (
"errors"
"fmt"
"os"
)
func main() {
f, err := os.Open("test.txt")
if err != nil {
var pErr *os.PathError
if errors.As(err, &pErr) {
fmt.Println("Failed to open file at path", pErr.Path)
return
}
fmt.Println("Generic error", err)
return
}
fmt.Println(f.Name(), "opened successfully")
}
If you are wondering why pErr is a pointer, the reason is, the error interface is implemented by the pointer of PathError and hence pErr is a pointer. The below code shows that *PathError implements the error interface.
The As function requires the second argument to be a pointer to the type that implements the error. Hence we pass &perr.
func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }
2. Retrieving more information using methods
type DNSError struct {
...
}
func (e *DNSError) Error() string {
...
}
func (e *DNSError) Timeout() bool {
...
}
func (e *DNSError) Temporary() bool {
...
}
package main
import (
"errors"
"fmt"
"net"
)
func main() {
addr, err := net.LookupHost("golangbot123.com")
if err != nil {
var dnsErr *net.DNSError
if errors.As(err, &dnsErr) {
if dnsErr.Timeout() {
fmt.Println("operation timed out")
return
}
if dnsErr.Temporary() {
fmt.Println("temporary error")
return
}
fmt.Println("Generic DNS error", err)
return
}
fmt.Println("Generic error", err)
return
}
fmt.Println(addr)
}
3. Direct comparison
The Glob function of the filepath package is used to return the names of all files that matches a pattern. This function returns an error ErrBadPattern when the pattern is malformed.
ErrBadPattern is defined in the filepath package as a global variable.
var ErrBadPattern = errors.New("syntax error in pattern")
errors.New() is used to create a new error. We will discuss this in detail in the next tutorial.
ErrBadPattern is returned by the Glob function when the pattern is malformed.
package main
import (
"errors"
"fmt"
"path/filepath"
)
func main() {
files, err := filepath.Glob("[")
if err != nil {
if errors.Is(err, filepath.ErrBadPattern) {
fmt.Println("Bad pattern error:", err)
return
}
fmt.Println("Generic error:", err)
return
}
fmt.Println("matched files", files)
}