设为首页 加入收藏

TOP

golang中的错误处理(二)
2023-07-23 13:30:32 】 浏览:59
Tags:golang
fmt.Println(err) } }
  1. 首先我们自定义了ForbiddenError的错误类型
  2. 我们实现了error接口
  3. 访问数据库抛出原始错误
  4. 上层返回ForbiddenError类型的错误
go run 9.go
Forbidden: permission denied

当然我们也可以不用创建自定义错误的类型,去包装错误添加上下文:

package main

import (
	"fmt"
	"github.com/pkg/errors"
)

type Courseware struct {
	Id int64
	Code string
	Name string
}


func getCourseware(id int64) (*Courseware, error) {
	courseware, err := getFromDB(id)
	if err != nil {
		return nil, fmt.Errorf("another wrap err: %w", err) // 1
	}
	return courseware, nil
}

func getFromDB(id int64) (*Courseware, error) {
	return nil, errors.New("permission denied")
}

func main() {
	_, err := getCourseware(11)
	if err != nil {
		fmt.Println(err)
	}
}
  1. 使用%w包装错误

使用这的好处是我们可以追溯到源错误,从而方便我们做一些特殊的处理。

还有一种方式是使用:

return nil, fmt.Errorf("another wrap err: %v", err)

%v的方式不会包装错误,所以无法追溯到源错误,但往往有时候我们会选择这种方式,而不用%w的方式。%w的方式虽然能包装源错误,但往往我们会通过源错误去做一些处理,假如源错误被修改,那包装这个源错误的相关错误都需要做响应变化。

3、错误类型判断

我们扩展一下上面查询课件的例子。现在我们有这样的判断,如果传进来的id不合法我们返回400错误,如果查询数据库报错我们返回500错误,我们可以像下面这样写:

package main

import (
	"fmt"
	"github.com/pkg/errors"
)

type Courseware struct {
	Id int64
	Code string
	Name string
}

type ForbiddenError struct {
	Err error
}

func (e *ForbiddenError) Error() string {
	return "Forbidden: " + e.Err.Error()
}

func getCourseware(id int64) (*Courseware, error) {
	if id <= 0 {
		return nil, fmt.Errorf("invalid id: %d", id)
	}
	courseware, err := getFromDB(id)
	if err != nil {
		return nil, &ForbiddenError{err}
	}
	return courseware, nil
}

func getFromDB(id int64) (*Courseware, error) {
	return nil, errors.New("permission denied")
}

func main() {
	_, err := getCourseware(500) // 我们可以修改这里的id看下打印的结构
	if err != nil {
		switch err := err.(type) {
		case *ForbiddenError:
			fmt.Println("500 err: ", err)
		default:
			fmt.Println("400 err: ", err)
		}
	}
}
go run 9.go
500 err:  Forbidden: permission denied

这样看起来好像也没什么问题,现在我们稍微修改下代码,把上面ForbiddenError包装一下:

package main

import (
	"fmt"
	"github.com/pkg/errors"
)

type Courseware struct {
	Id int64
	Code string
	Name string
}

type ForbiddenError struct {
	Err error
}

func (e *ForbiddenError) Error() string {
	return "Forbidden: " + e.Err.Error()
}

func getCourseware(id int64) (*Courseware, error) {
	if id <= 0 {
		return nil, fmt.Errorf("invalid id: %d", id)
	}
	courseware, err := getFromDB(id)
	if err != nil {
		return nil, fmt.Errorf("wrap err: %w", &ForbiddenError{err}) // 这里包装了一层错误
	}
	return courseware, nil
}

func getFromDB(id int64) (*Courseware, error) {
	return nil, errors.New("permission denied")
}

func main() {
	_, err := getCourseware(500)
	if err != nil {
		switch err := err.(type) {
		case *ForbiddenError:
			fmt.Println("500 err: ", err)
		default:
			fmt.Println("400 err: ", err)
		}
	}
}
go run 9.go
400 err:  wrap err: Forbidden: permission denied

可以看到我们的Forbidden错误进到了400里面,这并不是我们想要的结果。之所以会这样,是因为在ForbiddenError的外面又包装了一层Error错误,使用类型断言的时候判断出来的是Error错误,所以进到了400分支。

这里我们可以使用errors.As方法,它会递归调用Unwrap方法,找到错误链中第一个与target匹配的方法:

package main

import (
	"fmt"
	"github.com/pkg/errors"
)

typ
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Go接口嵌套的使用 下一篇go打印hello world、go语言的注释..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目