马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
颠末前面三节高代码强度的学习,信托各人都已经有点累了,本节我们不发急继承“赶路”,苏息半晌!我们换个轻松点的话题,聊一聊咱们项目定制化Error--AppError 怎么支持Go语言的 errors.Is 判断,以及项目预界说的那些Error在现实利用过程中某些环境下会出现循环引用的题目,我们会利用一个原型计划模式来办理这个题目。
项目定制化Error 回首
在界说项目 Error 实现错误链和发生位置记载这篇文章中我们给项目界说了自己的Error范例 AppError
- type AppError struct {
- code int `json:"code"`
- msg string `json:"msg"`
- cause error `json:"cause"`
- occurred string `json:"occurred"`
- }
复制代码 目的是为了通过自己的封装让Go的Error能支持错误缘故原由和发生位置的记载。同时我们还为项目的开辟预界说了很多Error变量。
- // 用户模块相关错误码 10000100 ~ 1000199
- var (
- ErrUserInvalid = newError(10000101, "用户异常")
- ErrUserNameOccupied = newError(10000102, "用户名已被占用")
- ErrUserNotRight = newError(10000103, "用户名或密码不正确")
- )
- // 商品模块相关错误码 10000200 ~ 1000299
- var (
- ErrCommodityNotExists = newError(10000200, "商品不存在")
- ErrCommodityStockOut = newError(10000201, "库存不足")
- )
- // 购物车模块相关错误码 10000300 ~ 1000399
- var (
- ErrCartItemParam = newError(10000300, "购物项参数异常")
- ErrCartWrongUser = newError(10000301, "用户购物信息不匹配")
- )
复制代码 在 Go项目Error的同一管理和处置惩罚发起 中我发起必要返回给客户端返回约定好的错误码的错误都在这里预先界说。而对于一些像DB、存储之类错误产生的Error 无需告知客户端明白缘故原由只必要让客户端发生了服务端内部错误的环境、大概不知道怎么处置惩罚的底层错误,我们先同一用Wrap方法把它包装成应用的AppError。
- err = DBMaster().WithContext(ud.ctx).Create(userModel).Error
- if err != nil {
- err = errcode.Wrap("UserDaoCreateUserError", err)
- return nil, err
- }
复制代码 在计划的过程中,以为已经够全面了,但是只要真正把它来开辟需求时,照旧能发现有题目的,具体什么题目呢? 我们继承往下看。
怎么让自界说Error支持Go的errors.Is判断
想让Error支持Go的errors.Is 判断,我们先来看看errors.Is 方法里到底是怎么判断Error是不是给定的目的错误的,其源码如下:
- func Is(err, target error) bool {
- if target == nil {
- return err == target
- }
- isComparable := reflectlite.TypeOf(target).Comparable()
- for {
- if isComparable && err == target {
- return true
- }
- if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
- return true
- }
- if err = Unwrap(err); err == nil {
- return false
- }
- }
- }
复制代码 其源码中逻辑是会一层层地解包error,每层的error都去看看是否已经实现了 interface{ Is(error) bool } 这个接口,如果实现了调用该层error的Is方法举行判断,如果跟给定error不相称大概没有实现Is接口,则继承用Uwrap解包,解到不能解为止 (err == nil)。
以是这里给我们预留了两个接口,我们让AppError实现 Is 和 Uwrap 方法后,它也就支持Go的 errors.Is 判断啦。
下面我们在 common/errcode/error.go 中到场这两个方法的实现。
- package errcode
- func (e *AppError) UnWrap() error {
- return e.cause
- }
- // Is 与上面的UnWrap一起让 *AppError 支持 errors.Is(err, target)
- func (e *AppError) Is(target error) bool {
- targetErr, ok := target.(*AppError)
- if !ok {
- return false
- }
- return targetErr.Code() == e.Code()
- }
复制代码 关于项目自界说Error的优化,在课程中我还利用了这里利用计划模式里的原型模式, 把项目预界说的全局错误都是看成原型-prototype,包管我们既能规范管理我们项目的错误码,也能更自由放心地在步伐中利用它们。
干系内容和过细的实今世码,都涵盖在专栏中,现在扫码订阅专栏,一起到场学习吧
本专栏分为五大部分,大部分内容已经更新完成
- 第一部分先容让框架变得好用的诸多实战本事,好比通过自界说日志
门面让项目日志 更简单易用、支持主动记载哀求的追踪信息和步伐位置信息、通过自界说Error在实现Go error接口的同时支持给给错误添加错误链,方便追溯错误源头。
- 第二部分:讲授项目分层架构的计划和分别业务模块的方法和标准,让你以后无论遇到什么项目都能按这套标准自己分别出模块和逻辑分层。背面几个部分均是该部分所讲内容的实践。
- 第三部分:计划实现一个套支持多平台登录,Token泄漏检测、同平台多装备登录互踢功能的用户认证体系,这套用户认证体系既可以在你将来开辟产物时直策应用
- 第四部分:商城app C端接口功能的实现,强化分层架构实现的讲授,这里还会讲授用责任链、战略和模版等计划模式去办理订单结算促销、付出方式付进场景等多种多样的现实题目。
- 第五部分:单元测试、项目Docker镜像、K8s摆设和服务保障干系的一些根本内容和注意事项
|