首页 > 其他分享 >golang error 使用

golang error 使用

时间:2022-12-11 23:11:37浏览次数:49  
标签:errors err frame error golang func 使用 SameErr

前言

Go的编程中, error的使用场景数不胜数, 主要就是用来处理各种异常情况.

长久以来, 我的使用方式都是这样的:

err := errors.New("fail")
if err != nil{
  //do somethine...
}

简单易懂.

但是, 如果我们的调用链是这样的func1 -> func2 -> func3 -> func4 -> func5, 此时func5发生错误, error逐层向上传递, func1拿到错误后, 因为缺少堆栈信息, 很难根据error还原出错场景.

那么, 根据这个问题, 又该如何处理呢? 很简单, 函数拿到error后, 在其中添加当前上下文信息后再返回不就行了么? 类似于这样:

func func4() error {
	err := func5()
	if err != nil {
		return errors.New(err.Error() + "--func4")
	}
	return nil
}

这当然可以. 但是上层还可能根据不同的error进行不同的异常处理, 这样的话, 使用err == SameErr的判断条件就不好使了.

那么, 如何能够在error中添加信息的同时, 又不丢失原始error的信息呢?

其实, 官方已经做好了类似的支持.

error

Gofmt库中有这样一个error:

type wrapError struct {
	msg string
	err error
}
func (e *wrapError) Error() string {
	return e.msg
}
func (e *wrapError) Unwrap() error {
	return e.err
}

它提供了一个Error方法来实现error接口, 同时还会保存原始的err信息, 可以通过Unwrap获得. 这不就是我们需要得么?

官方对其的使用进行了封装, 包含了:

  1. 对异常进行包装
  2. 判断指定异常是否存在与包装链中
  3. 从包装链中提取指定类型的异常
// 对 err 进行包装.
// 注意, 占位符必须为 %w, 否则返回的就是一个普通 error
err1 := fmt.Errorf("func4: %w", err)

// 判断 err1 中是否包含 SameErr 这个错误
// 相当于对所有 error 依次解包并进行 == 的比较
if errors.Is(err1, SameErr) {
  // 存在 SameErr
}

// 从 err 中获取指定类型的错误
var sameErr *SameErrStruct
if errors.As(err, &sameErr) {
  // 成功从 err 中获取到 SameErr
}

// 对error 进行解包, 若失败返回 nil
retErr := errors.Unwrap(err1)

翻了翻几个方法的源码都比较简单, 在这里就不细述了.

调用栈

但是, 这样一层一层将调用信息返回去, 还是有些麻烦, 有没有什么办法, 能够直接将调用栈放进去呢? 或者说, 在Go中如何获取调用栈呢?

func getStack() {
	// 获取当前调用栈
	pcs := make([]uintptr, 64)
	pcNum := runtime.Callers(2, pcs) // skip 2 是为了跳过 Callers 及其内部函数
	// 调用栈解析
	frames := runtime.CallersFrames(pcs[:pcNum])
	for frame, more := frames.Next(); more; frame, more = frames.Next() {
		fmt.Printf("file: %s, line: %d, func: %s\n", frame.File, frame.Line, frame.Function)
	}
}

OK, 所谓大道至简, error也就这么点东西, 完全能够满足使用了. 再见

标签:errors,err,frame,error,golang,func,使用,SameErr
From: https://www.cnblogs.com/hujingnb/p/16974833.html

相关文章

  • 使用Python解析Windows系统日志
    目标要求:对Windows系统日志进行处理,并生成统计文件1.如何找到Windows系统日志?通常情况下,我们都是在Windows系统自带的事件查看器查看系统日志(使用win+x可以快速......
  • ListView的基本使用
    布局文件<ListViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/lv"/>创......
  • 配置WSL2使用windos代理
    配置WSL2使用本机代理设置Win10防火墙这一步是最重要的一步,也是最坑的一步,需要在Win10防火墙中允许V某进行公用和专用网络的访问!只要设置这个就可以了,不需要调整......
  • Mybatis Generator使用
    官方文档配置方式一1.在resources文件夹下创建一个目录mybatis-generator,在目录mybatis-generator下创建文件generatorConfig.xml(此处的目录名可任意取)  2. pom.x......
  • 使用网络爬虫自动抓取图书信息
    网络爬虫是一种从互联网上进行开放数据采集的重要手段。本案例通过使用Python的相关模块,开发一个简单的爬虫。实现从某图书网站自动下载感兴趣的图书信息的功能。主要实现的......
  • 使用kubeadm快速部署一个k8s集群
    kubeadm是官方社区推出的一个用于快速部署kubernetes集群的工具。这个工具能通过两条指令完成一个kubernetes集群的部署:#创建一个Master节点$kubeadminit#将一个N......
  • 如何使用Skopeo做一个优雅的镜像搬运工
    本章目录:0x00基础介绍0x01安装编译1.源码编译(静态)2.分发包安装3.容器安装运行0x02快速上手1.命令浅析2.Skopeo初体验Skopeologin/loout-远程仓库AuthSkopeoinspect......
  • Rust中super关键字和self关键字的使用
    随笔:fnfunction(){println!("functionglobal");}pubmodmod1{pubfnfunction(){super::function();println!("functionmod1");}pubmo......
  • 使用 dragonflydb 作为godns 的redis 存储
    玩法没变,可以参考我以前写的,主要是调整了redis为dragonflydb测试下参考docker-compose文件version:"3"services:redis:image:docker.dr......
  • SNMPWALK 安装与使用详解
     简介snmpwalk是SNMP的一个工具,它使用SNMP的GETNEXT请求查询指定OID(SNMP协议中的对象标识)入口的所有OID树信息,并显示给用户。通过snmpwalk也可以查看支持SNMP协议(可网管)......