Go语言入门到实战——00主目录
在上一讲中我们学习了Go语言的接口相关的知识,面向对象的学习就结束了。
一.Go的错误机制
1.go语言不支持异常处理。
2.error类型实现了error接口
type error interface{
Error() string
}
3.通过errors.New()来快速创建错误实例;//推荐使用这个方法
errors.New("程序错误!!!")
package test
import (
"errors"
"fmt"
"testing"
)
func getVal(arr []int, idx int) (int, error) {
if idx >= len(arr) || idx < 0 {
return 0, errors.New("idx more than length or negative")
}
return arr[idx], nil
}
func TestClient(t *testing.T) {
arr := []int{1, 2, 3, 4}
v, err := getVal(arr, 4)
if err == nil {
fmt.Println(v)
} else {
fmt.Println(err)
}
}
//这段程序与上面的区别在于给出了一种常见的在实践中
//区分错误类型的写法
package test
import (
"errors"
"fmt"
"testing"
)
var NegativeError = errors.New("idx negative")
var MoreError = errors.New("more than length")
func getVal(arr []int, idx int) (int, error) {
if idx >= len(arr) {
return 0, MoreError
} else if idx < 0 {
return 0, NegativeError
}
return arr[idx], nil
}
func TestClient(t *testing.T) {
arr := []int{1, 2, 3, 4}
v, err := getVal(arr, 4)
if err == NegativeError {
fmt.Println("负idx")
} else if err == MoreError {
fmt.Println("超过大小")
} else {
fmt.Println("正常大小", v)
}
}
二.panic和recover
1.painc
1.painc用于不可恢复的错误
2.painc退出前会执行defer指定的内容
这里我们需要将painc和os.Exit()进行一下对比:
1.os.Exit()在退出时不会执行defer指定的函数
2.os.Exit()不输出当前栈调用信息
package test
import (
"fmt"
"os"
"testing"
)
func TestPaincAndExit(t *testing.T) {
fmt.Println("finally")
os.Exit(-1)
}
package test
import (
"errors"
"fmt"
"testing"
)
func TestPaincAndExit(t *testing.T) {
fmt.Println("finally")
panic(errors.New("error occurs"))
}
从上面两段程序我们可以看出,panic输出的结果显示了当前调用栈的信息,而os.Exit的结果则是比较简单的。接下来我们加入defer继续比较。
package test
import (
"errors"
"fmt"
"testing"
)
func TestPaincAndExit(t *testing.T) {
defer func(x int) {
fmt.Println("finally", x)
}(1)//这种写法之前我们没有用到过,不过这里使用到了可以很明显的看出其用法
panic(errors.New("error occurs"))
//下面结果我们可以看出使用painc,在程序退出前执行了defer
}
package test
import (
"fmt"
"os"
"testing"
)
func TestPaincAndExit(t *testing.T) {
defer func(x int) {
fmt.Println("finally", x)
}(1)
os.Exit(-1)
//使用os.Exit()没有执行defer
}
2.recover
我们都知道在java和c++里面有try…catch…这样的结构,那么在go里面也有类似的。
package test
import (
"errors"
"fmt"
"testing"
)
func TestPaincAndExit(t *testing.T) {
defer func() {
if err := recover(); err != nil {
fmt.Println("recover from", err)
}
}()
panic(errors.New("error"))
}//从结果中我们发现了这时并没有报错
不过上面这种修复方式(只是把错误信息打印了一下)是非常危险的,这里给出两点建议:
1.上面这种只是打印一下错误的日志而简单的recover,可能会导致僵尸服务进程,就是这个
进程看起来是开着的,但是实际上啥也没干,而系统这是在进行health check(一般进行
健康检查就是看进程是否还或者),这个时候造成误判
2.解决办法就是采取用"let it crash"策略,也就是重启的方式