>简单错误
- 简单的错误指的是仅出现一次的错误,且在其他地方不需要捕获该错误、
- 优先使用errors.New来创建匿名变量来直接表示简单错误
- 如果有格式化的需求,使用fmt.Errorf
结构体指针的用法注意点
- defaultCheckRedirect函数中需要传入一个Request的结构体指针,在main函数中声明一个结构体req,然后传入&req即可
- defaulfCheckRedirect函数中需要传入一个[]*Request结构体指针数组,就是数组中存结构体指针,就在main函数中声明两个结构体,req和a,然后声明v := []*Request{&req, &a}即可。
- 如果想得到一个结构体指针数组的索引为0的元素的值,写法为*v[0],加*代表他的值,不加*代表他的地址。
- 如果想得到一个普通结构体指针的值,也是加*
- 注意不能 var v [2]*Request,然后再v[0].x = 0,这样是不行的,因为结构体指针没有初始化,默认是 v[nil,nil],所以直接v[0].x=0会报空指针错误 ,所以使用结构体指针时一定要初始化,写法为v := []*Request{&req, &a}
package main
import (
"errors"
"fmt"
)
type Request struct {
x int
}
func defaultCheckRedirect(req *Request, via []*Request) error {
if len(via) > 1 {
return errors.New("stopped after 1 redirects")
}
return nil
}
func main() {
var req Request
req.x = 1
var a Request
a.x = 0
v := []*Request{&a, &req}
err := defaultCheckRedirect(&req, v)
if err != nil {
fmt.Println(err)
}
fmt.Println(req, *v[1])
}
运行结果
stopped after 1 redirects
{1} {1}
>错误的Wrap和UnWrap
- 错误的Wrap实际上是提供了一个error嵌套另一个error的能力,从而生成一个error的跟踪器
- 在fmt.Errorf中使用%w关键字来讲一个错误关联至错误链中
fmt.Errorf嵌套错误
package main
import (
"errors"
"fmt"
)
type Request struct {
x int
}
func defaultCheckRedirect(req *Request, via []*Request) error {
if len(via) > 1 {
return errors.New("stopped after 1 redirects")
}
return nil
}
func defaultCheckRedirects() error {
var req Request
req.x = 1
var a Request
a.x = 0
v := []*Request{&a, &req}
err := defaultCheckRedirect(&req, v)
if err != nil {
return fmt.Errorf("reading srcfiles list : %w", err)
}
return nil
}
func main() {
err := defaultCheckRedirects()
if err != nil {
fmt.Println(err)
}
}
.
>错误判定
- 判定一个错误是否为特定错误,使用errors.Is
- 不同于使用==,使用该方法可以判定错误链上的所有错误是否含有特定的错误
- 在错误链上获取特定种类的错误,使用errors.As
>panic
- 不建议在业务代码中使用panic
- 调用函数不包含recover会造成程序崩溃
- 若问题可以被屏蔽或解决,建议使用error代替panic
- 当程序启动阶段发生不可逆转的错误时,可以在init或main函数中使用panic
>recover
- recover只能在被defer的函数中使用
- 嵌套无法生效
- 只在当前goroutine(协程)生效
- defer的语句是后进先出
- 如果需要更多的上下文信息,可以recover后在log中记录当前的调用栈
小结
-
error尽可能提供简明的上下文信息链。方便定位问题
-
panic用于真正异常的情况
-
recover生效范围,在当前goroutine的被defer的函数中生效