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", nilcase string:return " string", nildefault: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)
}