小熊今天有意外收获,忍不住给大家分享我愉快的心情!昨天中午下楼取外卖的时候被一个同事认出来了,他问我:“是不是【编程三分钟】的作者,文章写的不错”。

你知道吗!我当时就是一愣,然后差点感动到哭出来,虽然小熊的号比不上大牛的号,不能随便发一篇文章都有成千上万的阅读量;但是非常开心的是,我还有你们,默默的关注我,爱你们~!

golang

异常处理思想

gotry catchtry catchtry
go
nilif

所以异常应该总是掌握在我们的手上,保证每次操作产生的影响达到最小,保证程序即使部分地方出现问题,也不会影响整个程序的运行,及时的处理异常,这样就可以减轻上层处理异常的压力。

同时也不要让未知的异常使你的程序崩溃。

异常的形式

我们应该让异常以这样的形式出现

func Demo() (int, error)

我们应该让异常以这样的形式处理(卫述语句)

_,err := errorDemo()
	if err!=nil{
		fmt.Println(err)
		return
	}

自定义异常

00
func divisionInt(a, b int) (int, error) {
	if b == 0 {
		return -1, errors.New("除数不能为0")
	}

	return a / b, nil
}

这个函数应该被这么调用

a, b := 4, 0
res, err := divisionInt(a, b)
if err != nil {
	fmt.Println(err.Error())
	return
}
fmt.Println(a, "除以", b, "的结果是 ", res)

可以注意到上面的两个知识点

errors.New("字符串")err.Error()

只要记得这些,你就掌握了自定义异常的基本方法。

errors.New("字符串")fmt.Errorf
err = fmt.Errorf("产生了一个 %v 异常", "喝太多")

详细的异常信息

errors
errorserrorErrorstring
type error interface {
	Error() string
}

只要结构体实现了这个方法就行,源码的实现方式如下

type errorString struct {
	s string
}

func (e *errorString) Error() string {
	return e.s
}

// 多一个函数当作构造函数
func New(text string) error {
	return &errorString{text}
}
error

这个自定义异常可以在报错的时候存储一些信息,供外部程序使用

type FileError struct {
	Op   string
	Name string
	Path string
}
// 初始化函数
func NewFileError(op string, name string, path string) *FileError {
	return &FileError{Op: op, Name: name, Path: path}
}
// 实现接口
func (f *FileError) Error() string {
	return fmt.Sprintf("路径为 %v 的文件 %v,在 %v 操作时出错", f.Path, f.Name, f.Op)
}

调用

f := NewFileError("读", "README.md", "/home/how_to_code/README.md")
fmt.Println(f.Error())

输出

路径为 /home/how_to_code/README.md 的文件 README.md,在 读 操作时出错

defer

上面说的内容很简单,在工作里也是最常用的,下面说一些拓展知识。

Godeferdefer

比如下面的例子是在一个函数内的三条语句,他是这么怎么执行的呢?

defer fmt.Println("see you next time!")
defer fmt.Println("close all connect")
fmt.Println("hei boy")
defer
hei boy
close all connect
see you next time!
deferc++
defer
tcp
defer

panic

defer
Gopaincgoroutinedefer

有时候在程序运行缺乏必要的资源的时候应该手动触发宕机(比如配置文件解析出错、依赖某种独有库但该操作系统没有的时候)

defer fmt.Println("关闭文件句柄")

panic("人工创建的运行时异常")

报错如下

报错示例

panic recover

panic

然后再借助运维监控系统对日志的监控,发送告警给运维、开发人员,进行紧急修复。

语法如下:

func divisionIntRecover(a, b int) (ret int) {
	defer func() {
		if err := recover(); err != nil {
			// 打印异常,关闭资源,退出此函数
			fmt.Println(err)
			ret = -1
		}
	}()

	return a / b
}

调用

var res int
	datas := []struct {
		a int
		b int
	}{
		{2, 0},
		{2, 2},
	}

	for _, v := range datas {
		if res = divisionIntRecover(v.a, v.b); res == -1 {
			continue
		}
		fmt.Println(v.a, "/", v.b, "计算结果为:", res)
	}

输出结果

runtime error: integer divide by zero
2 / 2 计算结果为: 1
panicrecoverdeferrecover
go
github