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. volatile 关键字笔记

    你应该知道的 volatile 关键字 当一个变量被 volatile 修饰时,任何线程对它的写操作都会立即刷新到主内存中,并且会强制让缓存了该变量的线程中的数据清空,必须从主内存重新读取最新数据. ...

  2. maven项目多环境打包问题

    1.xxx-api是基于springboot的模块 2.配置文件 application.properties spring.profiles.active=@activeEnv@ applicati ...

  3. GPU特征处理技术

    GPU特征处理技术 GPU和CPU有何不同? 现代片上系统(SoC)通常集成中央处理器(CPU)和图形处理器(GPU).设计不同,这可能更取决于处理的数据集的类型. CPU经过优化,可以一次对几块数据 ...

  4. 如何在Python中加速信号处理

    如何在Python中加速信号处理 This post is the eighth installment of the series of articles on the RAPIDS ecosyst ...

  5. CVPR2020论文解析:视频语义检索

    CVPR2020论文解析:视频语义检索 Fine-grained Video-Text Retrieval with Hierarchical Graph Reasoning 论文链接:https:/ ...

  6. AIoT 2020 年分析

    AIoT 2020 年分析 2020年,从智能手机到智能手表,从智能摄像头到智能汽车,随着AI.芯片.云计算.通信等基础技术的逐渐成熟,又一个行业来到了历史性的时刻--AIoT. 从"万物互 ...

  7. 开发平台支持Arm Cortex-M的微控制器上人工智能训练

    开发平台支持Arm Cortex-M的微控制器上人工智能训练 Development platform enables AI training on Arm Cortex-M-based microc ...

  8. spring如何集成第三方框架? 比如mybatis

    实体Bean的创建: 1: 基于class构建, 2: 构造方法构建 3: 静态工厂方法创建 4: FactoryBean构建 spring如何集成第三方框架? 比如mybatis 在mybatis中 ...

  9. 「题解」300iq Contest 2 B Bitwise Xor

    本文将同步发布于: 洛谷博客: csdn: 博客园: 简书. 题目 题目链接:gym102331B. 题意概述 给你一个长度为 \(n\) 的序列 \(a_i\),求一个最长的子序列满足所有子序列中的 ...

  10. 【NX二次开发】Block UI 指定点

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