Error是Go语言开发中最基础也是最重要的部分,跟其他语言的try catch的作用基本一致,想想在PHP JAVA开发中,try catch 不会使用,或者使用不灵活,就无法感知到程序运行中出现了什么错误,是特别可怕的一件事。

Error 基础

Golang中 error类型就是一个最基本interface,定义了一个Error()的方法

type error interface {
Error() string
}

平常使用最多的是这样的

errors.New("error")

在Golang中errors.New这样定义的

func New(text string) error {
return &errorString{text}
} // errorString is a trivial implementation of error.
type errorString struct {
s string
} func (e *errorString) Error() string {
return e.s
}

其实是返回了一个errorString的结构体,这个结构体实现了Error()方法,所以实现了error interface

看下Error在项目开发中是怎么使用的?

1.定义Error变量

在一段代码里面可能返回了很多个error,我怎么判断这个error是哪一种呢?

是这样的吧

var ERR_MSG = "error"
if err.Error() == ERR_MSG

这样的话,多个第三方类库和自己项目的错误描述要是一致的话就无法比较出来了,其实不应该是这样的。

我们看下 beego里面orm是怎么定义的,从上面的基础我们知道errors.New返回的是errorString的指针

var (
ErrTxHasBegan = errors.New("<Ormer.Begin> transaction already begin")
ErrTxDone = errors.New("<Ormer.Commit/Rollback> transaction not begin")
ErrMultiRows = errors.New("<QuerySeter> return multi rows")
ErrNoRows = errors.New("<QuerySeter> no row found")
ErrStmtClosed = errors.New("<QuerySeter> stmt already closed")
ErrArgs = errors.New("<Ormer> args error may be empty")
ErrNotImplement = errors.New("have not implement")
)

其实都是使用指针判断的

看下怎么使用,下面是伪代码

err := this.QueryTable(this.table).Filter("id", id).One(data)
if err != nil && err != orm.ErrNoRows {
return err
}
return nil

这种其实在Golang 源码或者第三方类库里面用的比较多,缺点就是耦合,调用者使用一个第三方类库,需要知道的它的代码里面的错误类型,而且还需要在项目中使用这些错误类型的变量进行比较,第一次使用的开发者,很难想到需要这么使用。

2.自定义自己的Error

以前PHP的项目Exception里面会定义自己的错误码 code。

Golang中我们也可以定义自己的Error类型,然后使用断言决定是那种Error来获取更多的错误数据,看下下面的示例代码,了解下自定义Error的简单使用

type SelfError struct {
Code int
Err error
} func (this *SelfError) Error() string {
return this.Err.Error()
}
func (this *SelfError) GetCode() int {
return this.Code
} func OpenFile(name string) error {
err := os.Rename("/tmp/test","/tmp/test1")
if err != nil {
return &SelfError{-1001, err}
}
return nil
} func main() {
err := OpenFile("test")
switch erro := err.(type) {
case nil:
fmt.Println("success")
case *SelfError:
fmt.Println(erro.Error(),erro.Code)
case error:
fmt.Println(erro.Error())
}
}

还有一种用法就是判断error类型是否是自定义如果是,就返回自定义的属性

func main() {
err := OpenFile("test")
serr, ok := err.(*SelfError)
if ok {
fmt.Println(serr.GetCode())
}
}

可以看到都是通过断言去判断error是否是自定义的Error,如果是,就使用自定义的Error自己的属性和方法。

耦合,调用者需要使用switch或者断言才能使用自定义的Error的属性。

3.Wrap Errors的使用

wrap errors的使用应该是项目对error的处理运用最多的一种,可以方便的加入使用时的上下文。

Wrap Errors 顾名思义就是把error一层层的包装,最外层拿到的是error的一个堆栈信息,根据堆栈信息一直可以追踪到第一个引起error 的调用代码。

需要使用这个包

github.com/pkg/errors

看下代码示例

package main

import (
"fmt"
"github.com/pkg/errors"
"os"
) func ModelFile() error {
err := os.Rename("/tmp/test","/tmp/test1")
if err != nil {
return errors.Wrap(err, "model_rename_fail")
}
return nil
} func LogicFile() error {
err := ModelFile()
if err != nil {
return errors.Wrap(err, "logic_rename_fail")
}
return nil
} func main() {
err := LogicFile()
if err != nil {
fmt.Printf("error:%v", errors.Cause(err))
fmt.Printf("%+v", err)
}
}

看下执行结果的堆栈

error:rename /tmp/test /tmp/test1: no such file or directoryrename /tmp/test /tmp/test1: no such file or directory
model_rename_fail
main.ModelFile
/data/www/go/src/test1/main.go:12
main.LogicFile
/data/www/go/src/test1/main.go:18
main.main
/data/www/go/src/test1/main.go:26
runtime.main
/usr/local/go/src/runtime/proc.go:203
runtime.goexit
/usr/local/go/src/runtime/asm_amd64.s:1357
logic_rename_fail
main.LogicFile
/data/www/go/src/test1/main.go:20
main.main
/data/www/go/src/test1/main.go:26
runtime.main
/usr/local/go/src/runtime/proc.go:203
runtime.goexit
/usr/local/go/src/runtime/asm_amd64.s:1357

使用的简单规则

这么多使用方法,到底应该用哪一种,大致建议应该是这样的

  1. 需要做比较错误类型的时候,肯定是第一种方式使用,目前也没有更好的方式
  2. 需要加入自己项目的错误码或者复杂的一些上下文,可能就需要使用第二种自定义错误类型
  3. 需要依赖第三方的类库,这个类库可能也不太稳定,那么wrap error优势就比较明显,可以打印记录堆栈,方便定位。
  4. 一些常用的简单项目,就只需在触发错误的地方记录上下文打上日志,直接返回error就可以了,这是最简单最方便的。

golang开发:Error的使用的更多相关文章

  1. Golang开发支持平滑升级(优雅重启)的HTTP服务

    Golang开发支持平滑升级(优雅重启)的HTTP服务 - tabalt的博客 http://tabalt.net/blog/graceful-http-server-for-golang/ http ...

  2. Golang 开发技能图谱

    # Golang 开发技能图谱 ## Go 语言环境搭建- Go 安装- GOPATH 与工作空间- Go 命令- Go开发工具 ## GO 语言编程基础- 关键词和语法(Language Synta ...

  3. 十分钟学会Golang开发gRPC服务

    gRPC是Google发起的一个开源RPC框架,使用HTTP/2传输协议,使用Protocol Buffers编码协议,相比RESTful框架的程序性能提高不少,而且当前流行的编程语言基本都已经支持. ...

  4. 用golang开发系统软件的一些细节

    用golang开发系统软件的一些细节 作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 (本文的pdf版本) ...

  5. 使用golang 开发的 andriod应用

    最近在捣鼓一个东东,就是使用golang开发andriod应用.说起来简单操作起来还挺麻烦,中间又学习了很多东西.比如ubuntu,docker,angular,ionic,jquery mobile ...

  6. golang开发android环境搭建_window

    golang开发android环境搭建介绍 一 安装依赖软件: git:版本管理 go:  go开发环境(版本>=1.5),可直接下载window版的go安装包. android studio: ...

  7. Windows下visual studio code搭建golang开发环境

    Windows下visual studio code搭建golang开发环境 序幕 其实环境搭建没什么难的,但是遇到一些问题,主要是有些网站资源访问不了(如:golang.org),导致一些包无法安装 ...

  8. linux golang开发环境配置(离线方式)

    <获取开发工具>     到https://www.golangtc.com/download 下载安装包, 根据自己的系统选择合适的开发包,这里选择go.1.9.2.linux-amd6 ...

  9. miniblink+golang开发windows gui应用

    golang的优点自不必说了,这么好的语言怎么能缺少界面库呢?所以我使用miniblink开发了一个可以用html,css,js开发界面的浏览器,通过它你能为你的golang开发简单的界面.说白了其实 ...

随机推荐

  1. Guava-retry,java重试组件

    使用场景 在日常开发中,我们经常会遇到需要调用外部服务和接口的场景.外部服务对于调用者来说一般都是不可靠的,尤其是在网络环境比较差的情况下,网络抖动很容易导致请求超时等异常情况,这时候就需要使用失败重 ...

  2. SLAM相机定位

    SLAM相机定位 摘要 深度学习在相机定位方面取得了很好的结果,但是当前的单幅图像定位技术通常会缺乏鲁棒性,从而导致较大的离群值.在某种程度上,这已通过序列的(多图像)或几何约束方法解决,这些方法可以 ...

  3. 如何在GPU上优化卷积

    本文将演示如何在TVM中编写高性能的卷积实现.以平方大小的输入张量和滤波器为例,并假设卷积的输入量很大.使用不同的布局来存储数据,以实现更好的数据局部性.缓冲区布局为HWCN,代表高度,宽度,通道,批 ...

  4. Gbps接口面向汽车应用

    Gbps接口面向汽车应用 Gbps interfaces target automotive appications 巴黎--不久前,移动通信行业是一个领着芯片商的领头羊,命令坐着,脚跟着,然后翻身. ...

  5. JS使用Enter事件将输入的字符倒叙输出

    在JavaScript中执行当用户按下Enter键位时将用户输入的字符倒叙输出! HTML代码: <body> <form id="form1" runat=&q ...

  6. 【NX二次开发】Block UI 指定坐标系

    属性说明 属性   类型   描述   常规           BlockID    String    控件ID    Enable    Logical    是否可操作    Group    ...

  7. 如何使用perf进行程序分析

    1.安装. sudo apt-get install linux-tools 如果提示没有可安装候选.请输入: sudo apt-get install linux-perf-version 其中ve ...

  8. 百炼 POJ2393:Yogurt factory【把存储费用用递推的方式表达】

    2393:Yogurt factory 总时间限制:  1000ms 内存限制:  65536kB 描述 The cows have purchased a yogurt factory that m ...

  9. Web端在线实时聊天,基于WebSocket(前后端分离)

    这是一个简易的Demo,已经实现了基础的功能 之前一直想实现一个实时聊天的系统,一直没有去实践他.有一天吃饭的时候扫码点菜,几个人点菜能够实时更新,当时就在想,这应该是同一种技术. 刚好前段时间项目上 ...

  10. 生成工作区设置文件settings.json

    先Ctrl+Shift+P,然后输入setting搜索 找到工作区设置(工作区,仅在当前打开的界面下生效,文档位置与根目录/.vscode/setting.json(可自己创建,也可不创建)) 选择之 ...