说是初识,并不是说第一次使用error和panic包,而是第一次特地去了解golang中的这两个机制。之前写代码一直追求达到目的就可以,很少静下心了解一门语言。需要就用,用过就丢。但是这几天由于没有任务,投出去的简历估计是石沉大海,杳无音讯了。这反而让我可以静下心来把每一个自己感兴趣的点了解清楚,甚至开始研究他的实现,写博客也只是为了让自己加深下理解,如果能帮助到别人那更是上天眷顾(如果我写错了,我感到十分抱歉,并十分感谢你们可以提出来或者帮我指引指引方向^_^),这种感觉还是很不错的,哈哈。
好吧,以上全是废话。
首先Golang中错误和异常是两个完全不同的概念。
大部分错误被认为是可以预期的,所以我们的程序中很多见类似`err := func()`这样的语句,对于这种模式肯定会相对麻烦,但是我觉得会使程序更加健壮,更加易于编程,就好像我们写的API接口,不管有没有取到数据,你要告诉我一个状态,如果出错了,出错的原因是什么。
而异常则是指:程序在运行时会捕获很多错误,这些错误大多是不可预期的,而这些错误会引发异常。一般来说,一旦异常发生,会导致程序停止运行,并立即执行defer函数中的内容,然后输出错误信息。
错误处理的方式有五种:
第一种是如果在子函数中发生错误,那么就应该返回给调用它的函数处理。可以选择直接将错误返回给调用函数,如果子函数中还需要添加一些错误的上下文信息,也可以使用fmt.Errorf()来构建一个包含更多信息的错误返回。
第二种如果错误是偶然发生的,比如我这个函数需要执行网络链接,不巧执行的时候网络刚好断了几秒,那这种错误我就可以通过多次执行跳过这种错误。
第三种如果错误发生后,程序无法继续运行,那我们可以输出错误信息并结束程序。需要注意的是,这种策略只应在main中执行。对库函数而言,应仅向上传播错误,除非该错误意味着程序内部包含不一致性,即遇到了bug,才能在库函数中结束程序。
第四种如果错误发生并不会影响程序大部分功能的执行,那么我们只需要通过log.Printf()函数来打印错误就可以了。
第五种有些无关紧要的错误,我们可以直接忽略,在函数运行返回值的时候用"_"代替error类型的返回值。
对于异常的处理相对情况就没有这么复杂了,因为panic是比较严重,不可预期的错误,所以Golang还是不鼓励我们过多使用panic的,如果可能应该使用错误机制来处理这些错误,这也会使我们的程序更加健壮。
如果程序一定要panic,我们又要对这次panic做一些处理,将程序从崩溃边缘拉回来的话,可以使用deferred函数中调用了内置函数recover。以下是《Go语言圣经》中的例子:
func soleTitle(doc *html.Node) (title string, err error) {
type bailout struct{}
defer func() {
switch p := recover(); p {
case nil:
// no panic
case bailout{}:
// "expected" panic
err = fmt.Errorf("multiple title elements")
default:
panic(p) // unexpected panic; carry on panicking
}
}()
// Bail out of recursion if we find more than one nonempty title.
forEachNode(doc, func(n *html.Node) {
if n.Type == html.ElementNode && n.Data == "title" &&
n.FirstChild != nil {
if title != "" {
panic(bailout{}) // multiple titleelements
}
title = n.FirstChild.Data
}
}, nil)
if title == "" {
return "", fmt.Errorf("no title element")
}
return title, nil
}
我们可以看到对于panic我们可以做有选择的恢复,通过recover内置函数可以获取panic value(就是panic函数调用是括号里的参数),如果panic是传入字面值为”bailout{}”, 那么我们就返回一个错误,如果panic没传入字面值我们就不返回也不处理,相当于忽视掉这次panic,当然这要看具体情况来定。剩下那种情况,执行panic相当于我们的defer什么也没做。
以上是Golang的错误和异常处理机制的处理策略,但是没有实例我们只领会他的意思肯定有些抽象,在《GO实战圣经》中5.4, 5.8,5.9,5.10是介绍的这部分内容,大家也可以去参考里边的例子。