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. [leetcode] 872. 叶子相似的树(周赛)

    872. 叶子相似的树 前序遍历,记录叶子节点即可 class Solution { private static String ans = ""; public boolean ...

  2. NVIDIA GPU上的随机数生成

    NVIDIA GPU上的随机数生成 NVIDIA CUDA随机数生成库(cuRAND)提供高性能的GPU加速的随机数生成(RNG).cuRAND库使用NVIDIA GPU中提供的数百个处理器内核,将质 ...

  3. VGG16迁移学习实现

    VGG16迁移学习实现 本文讨论迁移学习,它是一个非常强大的深度学习技术,在不同领域有很多应用.动机很简单,可以打个比方来解释.假设想学习一种新的语言,比如西班牙语,那么从已经掌握的另一种语言(比如英 ...

  4. Maven execution terminated abnormally (exit code 1) 完美解决

    https://www.pianshen.com/article/1477185745/ 找到本地仓库这个包中, 删掉,重新导入,,完美解决

  5. 【NX二次开发】开发好几年,还只会用ufusr?其他用户出口函数介绍

    用户出口(User Exit)是NX Open 中的一个重要概念.NX在运行过程中某些特定的位置存在规定的出口,当进程执行到这些出口时,NX会自动检查用户是否在此处已定义了指向内部程序位置的环境变量: ...

  6. 【Azure 机器人】微软Azure Bot 编辑器系列(3) : 机器人对话流中加入帮助和取消按钮功能 (The Bot Framework Composer tutorials)

    欢迎来到微软机器人编辑器使用教程,从这里开始,创建一个简单的机器人. 在该系列文章中,每一篇都将通过添加更多的功能来构建机器人.当完成教程中的全部内容后,你将成功的创建一个天气机器人(Weather ...

  7. 【模拟8.05】优美序列(线段树 分块 ST算法)

    如此显然的线段树,我又瞎了眼了 事实上跟以前的奇袭很像....... 只要满足公式maxn-minn(权值)==r-l即可 所以可以考虑建两颗树,一棵节点维护位置,一棵权值, 每次从一棵树树上查询信息 ...

  8. noip2007 总结

    统计数字 原题 某次科研调查时得到了n个自然数,每个数均不超过1500000000(1.5*10^9).已知不相同的数不超过10000个,现在需要统计这些自然数各自出现的次数,并按照自然数从小到大的顺 ...

  9. 老板防止我上班摸鱼,给我装了个chrome插件

    <铁柱幻想的摸鱼生活> 9:30:到达公司,开开电脑,收拾一下办公桌 9:40:吃个早餐,接杯水(一定要多喝水,一个肾结石同事的出院后的衷心建议) 10:00:打开"技术网站&q ...

  10. Docker笔记--ubuntu安装docker

    Docker笔记--ubuntu安装docker 1.更换国内软件源,推荐中国科技大学的源,稳定速度快(可选) sudo cp /etc/apt/sources.list /etc/apt/sourc ...