不捕获 error
典型的像如下代码:
func getBar()(*bar, err){
//some errors
if err := hasError(); err != nil{
return nil, err
}
//do sth
return new(bar), nil
}
func foo(){
b, _ := getBar()
b.DoSth() //panic
}
以下典型的 golang 代码看起来很烦,而且直接影响代码风格美观程度。
func getBar()(*bar, err){
//do sth
return 0, nil
}
func foo()error{
if b1, err := getBar(); err != nil{
return err
}
if b2, err := getBar(); err != nil{
return err
}
return nil
}
我在很多项目里看到新手或者从其他语言转过来的同学,喜欢写 if p, _ := getBar()
这样的代码,然后继续处理接下来的流程。这样做的问题在于你直接忽略掉了你所调用代码产生的错误,你内心默认的代码运行方式是:“我的代码一定会以正确的方式运行。”
在很多其他的语言里会有 try catch 这样的机制,可以让你在函数调用的外部直接捕获异常。当随之带来的问题是 try catch 是跨函数跨模块和函数的,容易出现抛出的异常被并不适合这个模块的代码模块去处理。
go 语言这个错误处理方式虽然丑陋,但简单有效。它这样做简单的让你把 error 直接丢给上一层,上一层可以决定这个错误是继续传递还是中止处理。当我把写 go 关于错误处理的思维方式转变成:不放过任何一个错误后,写代码的心智负担将得极低。我只需要关心当前的函数输入输出数据是否合法,以及调用其他函数时出错后选择继续还是中止。而且 go 语言这种小粒度的 error 处理方式几乎不用 care 错误的类型,遇到不合法 /异常 /错误 /非正常流程后只需要 error 继续 /中止一把梭即可。
不信你可以看看下面是如何用简单的错误处理是如何改掉 HTTP 200 一把梭的毛病。
func Query(w http.ResponseWriter, r *http.Request) {
var data RequestData
err := json.NewDecoder(r.Body).Decode(&data)
if err != nil{
w.WriteHeader( http.StatusBadRequest)
return
}
if data.Name == "not existed"{
w.WriteHeader( http.StatusNotFound)
return
}
w.WriteHeader( http.StatusOK)
return
}
某些 golang 的 web framework 会调用 recover 方法,以防止 HTTP server 崩溃。不得不说这是它提供的一种“助纣为虐”的方式让你去忽略掉某些致命的错误。这完全没必要,守护进程比 recover 要靠谱得多(还能自动获得重启大法的加成:) )。我个人认为在代码里面尽量不要调用任何 recover 的代码,尽量在代码部署到生产环境前测试发现所有可能的 panic 错误并修复掉。如果代码发生 panic 问题,肯定是有什么地方你没有想到或没设计好,你需要做的是修改代码而不是掩盖错误。
捕获所有错误你唯一需要付出的代价就是:多敲几个字。而付出的这点代价你将获得:底层成本的设计负担,无脑的心智负担,健壮的代码,严格的输入输出限定。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.