go设计者更偏向于C的error处理方式, 快速失败是更简单高效的
我们可以利用error接口和多返回值来实现异常传递
error可以利用变量来复用 等价判断
var outOfRangeError = errors.New("number out of range")
var unknownError = errors.New("unknown type error")
func doSomeThing01(i interface{
}) (string, error) {
switch value := i.(type) {
case int:
if value > 10 {
return "wrong", outOfRangeError
}
return " integer", nil
case string:
return " string", nil
default:
return " unknown", unknownError
}
}
判断异常时, 异常逻辑在前, 即使有复杂业务逻辑判断, 也同样是扁平结构
func TestDoSomething(t *testing.T) {
if msg01, err := doSomeThing01(1); err != nil {
t.Log(err)
} else {
t.Log(msg01)
}
if msg01, err := doSomeThing01(200); err != nil {
t.Log(err)
} else {
t.Log(msg01)
}
if msg01, err := doSomeThing01(false); err != nil {
t.Log(err)
} else {
t.Log(msg01)
}
}
但是也有类似java的异常捕获机制
通过panic抛出
通过defer来获取处理
通过recover使得程序继续运行
但是如果告警做的不好, 或者defer逻辑只是简单的记日志
Just let it crash!
那么更推荐让程序崩溃掉, 然后由运维层的恢复机制告警恢复, 健康检查这样也会检测到异常, 从而更好的解决本质问题
func doSomeThing02(i interface{
}) string {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
switch value := i.(type) {
case int:
if value > 10 {
panic(outOfRangeError)
}
return " integer"
case string:
return " string"
default:
panic(unknownError)
}
}
func TestDoSomething02(t *testing.T) {
msg01 := doSomeThing02(1)
t.Log(msg01)
msg02 := doSomeThing02(200)
t.Log(msg02)
msg03 := doSomeThing02(false)
t.Log(msg03)
}