Golang 错误处理
FBI WRINING
文章会牵扯到接口部分的内容,没有接触过的读者建议先去学习。
定义
在go中,错误被定义成一个接口(interface)
type error interface {
Error() string
}
使用
最简单的使用错误的方法就是用函数创建一个错误
简易版本
package main
import (
"errors"
"fmt"
)
func main() {
value := false
text, err := isu(value)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(text)
}
}
func isu(value bool) (string, error) {
if value == true {
return "true!!!!! ", nil
} else {
return "", errors.New("error! is false! ")
}
}
error! is false!
我们先看上面代码的核心部分:isu函数。
函数用if语句判断参数value的值是否为true,为true就返回一个字符串,而错误则为nil(没有错误)。
当为false就返回一个空字符串,而我们用errors里面的New函数(也是errors包里唯一一个函数)创建了一个包含有用信息的错误并返回。
转到main函数,我们创建了一个变量,并将他传入到isu函数内,由于变量值为false,所以isu函数将返回一个错误。
最后我们用if判断错误变量是否不为nil(有错误),有错误就输出错误信息。(但是这样也造成了大量的样板代码,所以设计者出来挨打)
除了errors包,fmt包里面也提供了类似的函数
package main
import (
"fmt"
)
func main() {
value := false
text, err := isu(value)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(text)
}
}
func isu(value bool) (string, error) {
if value == true {
return "true!!!!! ", nil
} else {
return "", fmt.Errorf("error! is %t! ", value)
}
}
error! is false!
都是一样的效果。不过他可以更灵活,而不是像最初的例子,字符串是“死”的(硬编码),因此个人也更推荐使用fmt包里的。
高级版本
想象一下,如果我们需要更详细的错误信息,比如文件名,你该怎么做?我们当然可以直接分割字符串提取信息,但是谁也不知道这个字符串会不会变,到时候变了就没辙了。
为此,我们可以自己定义一个错误类型,获取更详细的错误信息。
package main
import (
"fmt"
)
type FileError struct {
name string
}
func (self *FileError) Error() string {
return "File Error! "
}
func OpenFile(name string) (int32, error) {
return -1, &FileError{name}
}
func main() {
file, err := OpenFile("opengl_init.go")
if err != nil {
fmt.Println(err)
err_type := err.(*FileError)
fmt.Println(err_type.name)
} else {
fmt.Println("File is open. handle: %s ", file)
}
}
File Error!
opengl_init.go
在上面的代码里,我们定义了一个类型FileError(文件错误),并为他实现了Error方法来返回一个错误信息,这也代表他真正意义上成为了错误类型。
错误是产生出来的,所以我们需要一个能产生错误的函数。在这里我们定义了一个函数OpenFile(仅供演示,实际肯定是不同的),为了方便演示,我们直接返回错误。由于FileError结构体实现了error接口,所以返回值列表我们可以直接填error。
接着我们使用OpenFile函数,并且检查返回的err是否不为nil,由于我们直接返回了错误,所以if语句的分支我们就不用管了。
最后,我们打印了错误信息,一如既往很正常。重磅的来了!我们对err进行类型断言获得原始类型(*FileError),这样,我们就能访问到FileError结构体,获得文件名了!