Go 处理错误

如果你习惯了 try catch 这样的语法后,会觉得处理错误真简单,然后你再来接触 Go 的错误异常,你会发现他好复杂啊,怎么到处都是 error,到处都需要处理 error。

首先咱们需要知道 Go 语言里面有个约定,就是一个方法的返回参数,我们通常习惯的把错误当最后一个参数返回(这虽然官方在这点上没有做硬性规定,但是大家也都习惯这么做)。

至于为啥 Go 要这样去设计处理异常,咱们这种干饭人事就不去分析了,官方怎么设计咱们就怎么遵守就好了。

一、简单错误创建

1、 errors

我们可以使用 errors 包的 New 方法,传入一个字符串快速地创建。

Go 复制代码
var e error
e = errors.New("我是错误")

2、fmt

fmt 可以输出一些内容,同样他还能为我们创建错误。

Go 复制代码
var e error
e = fmt.Errorf("%s", "我还是错误")

其实错误对 Go 语言来说,其实就是一段字符串。

二、对错误进行编程

Go 语言中的错误定义是一个借口,只要是声明了 Error() string 这个方法,就意味着他就可以判定他是一个错误。

这是 Go 中的错误定义源码:

Go 复制代码
// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
type error interface {
 Error() string
}

1、自定义错误&使用

Go 复制代码
package main

import (
	"fmt"
)

type MyError string

// 实现了Error的接口
func (this MyError) Error() string {
	return string(this)
}
func main() {
	var e error
	e = MyError("自定义的错误")
	fmt.Println(e)
}

2、友好地返回错误

可以把 string 换成 struct ,同时加入很多我们自定义的属性

Go 复制代码
package main

import (
	"fmt"
)

type MyError struct {
	Code int
	Msg  string
}

func (this MyError) Error() string {
	return fmt.Sprintf("%d-%s", this.Code, this.Msg)
}

func NewMyError(code int, msg string) *MyError {
	return &MyError{Code: code, Msg: msg}
}

// FindUser 模拟下我们的业务方法
func FindUser() error {
	return NewMyError(404, "找不到内容")
}

func main() {
	var e error
	e = FindUser()
	fmt.Println(e)
}

三、错误的api

1、Is

官方为我们提供了 Is 方法的 API,他默认使用 == 将特定的错误与错误链中的错误进行比较,如果不一样,就会去调用错误实现的 Is 方法进行比较。

先去实现下 Is 这个方法,随后我们使用 errors.Is 进行比较

Go 复制代码
package main

import (
	"errors"
	"fmt"
	"log"
)

type MyError struct {
	Code int
	Msg  string
}

func (this MyError) Error() string {
	return fmt.Sprintf("%d-%s", this.Code, this.Msg)
}

func NewMyError(code int, msg string) *MyError {
	return &MyError{Code: code, Msg: msg}
}

// FindUser 模拟下我们的业务方法
func FindUser() error {
	return NewMyError(404, "找不到内容")
}

func (this *MyError) Is(target error) bool {
	log.Println("到这里来了....")
	if inputE, ok := target.(*MyError); ok {
		if inputE.Code == this.Code && inputE.Msg == this.Msg {
			return true
		}
	}
	return false
}

func main() {
	var e error
	e = FindUser()
	log.Println(e)

	if errors.Is(e, NewMyError(404, "找不到内容")) {
		log.Println("是 ErrorNotFind")
	} else {
		log.Println("不是 ErrorNotFind")
	}

	if errors.Is(e, NewMyError(405, "找不到内容")) {
		log.Println("是 ErrorNotFind")
	} else {
		log.Println("不是 ErrorNotFind")
	}

	if errors.Is(e, NewMyError(404, "这是xxx错误")) {
		log.Println("是 ErrorNotFind")
	} else {
		log.Println("不是 ErrorNotFind")
	}
}

还可以有复杂的结构体来表示错误

2、Unwrap

不大常用的 API ,标准库里面 fmt.Errorf 就是一个非常典型的使用案例

Go 复制代码
package main

import (
	"errors"
	"fmt"
	"log"
)

type MyError struct {
	Code int
	Msg  string
}

func (this MyError) Error() string {
	return fmt.Sprintf("%d-%s", this.Code, this.Msg)
}

func NewMyError(code int, msg string) *MyError {
	return &MyError{Code: code, Msg: msg}
}

// FindUser 模拟下我们的业务方法
func FindUser() error {
	return NewMyError(404, "找不到内容")
}

func (this *MyError) Unwrap() error {
	this.Msg = "hello" + this.Msg
	return this
}

func main() {
	var e error
	e = FindUser()
	log.Println("最原始的错误:", e)
	wE := errors.Unwrap(e)
	log.Println("加了上下文的错误:", wE)
}
相关推荐
m0_570466416 分钟前
代码随想录算法训练营第二十八天 | 买卖股票的最佳实际、跳跃游戏、K次取反后最大化的数组和
java·开发语言·算法
程序喵大人7 分钟前
分享个C++线程池的实现源码
开发语言·c++·线程池
不会吃萝卜的兔子31 分钟前
go webrtc - 1 go基本概念
开发语言·golang·webrtc
豌豆花下猫44 分钟前
Python 潮流周刊#118:Python 异步为何不够流行?(摘要)
后端·python·ai
要做朋鱼燕1 小时前
【C++】 priority_queue 容器模拟实现解析
开发语言·c++·笔记·职场和发展
jiaway1 小时前
【C语言】第四课 指针与内存管理
c语言·开发语言·算法
励志不掉头发的内向程序员1 小时前
C++进阶——继承 (1)
开发语言·c++·学习
秋难降1 小时前
SQL 索引突然 “罢工”?快来看看为什么
数据库·后端·sql
Access开发易登软件2 小时前
Access开发导出PDF的N种姿势,你get了吗?
后端·低代码·pdf·excel·vba·access·access开发
中国胖子风清扬3 小时前
Rust 序列化技术全解析:从基础到实战
开发语言·c++·spring boot·vscode·后端·中间件·rust