Go的标准库函数在发生错误时会返回error类型,比如常用的os.Open函数用来打开文件,错误时返回error:
func Open(name string) (*File, error)
那么究竟什么是error类型呢?其实很简单,error是一个接口,该接口只声明了一个方法Error(),返回值是string类型,用以描述错误:
type error interface {
Error() string
}
如何创建自己的error呢?当然可以自己实现这个接口,比如:
package main
import "fmt"
type MyError struct {
Desc string
}
func (myErr MyError) Error() string {
return myErr.Desc
}
func doSomething() error {
// ...
return MyError{"Logic Error!"}
}
func main() {
if err := doSomething(); err != nil {
fmt.Println(err)
}
}
但是更简单的方法是利用errors包中的New()函数直接创建error对象,errors包的内容仅有如下四行代码:
package errors
func New(text string) error { return &errorString{text} }
type errorString struct { text string }
func(e *errorString) Error() string { return e.text }
可以看到errors包的内部声明了一个 errorString 结构体,并用其中的text字段来表示错误描述,而不是直接用字符串来表示,这样做的好处是将错误描述封装了起来,防止我们在包外意外地改变错误描述。注意实现 error 接口的是 *errorString,而不是 errorString,这是为了让所有New返回的error对象都不相等:
一版情况下我们很少调用errors.New()来创建error对象,而是通过fmt包中提供的函数Errorf():
package fmt
import "errors"
func Errorf(format string, args ...interface{}) error {
return errors.New(Sprintf(format, args...))
}
可以看到fmt.Errorf()也是通过errors.New()来创建error对象。
*errorString 可能是最简单的error对象,但并不是唯一的error对象,比如syscall包中的Errno也是一个实现了error接口的类型。在Unix实现中,Errno的Error()方法通过查找错误列表返回错误信息:
package syscall
type Errno uintptr
var errors = [...]string {
: "operation not permitted",
: "no such file or directory",
// ...
}
func (e Errno) Error() string {
if <= int(e) && int(e) < len(errors) {
return errors[e]
}
return fmt.Sprintf("errno %d", e)
}
参考自《Go程序设计语言》