写 go 语言的一种不作不会死的方式 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
join
V2EX    Go 编程语言

写 go 语言的一种不作不会死的方式

  •  
  •   join
    leyafo 2022-07-22 22:05:41 +08:00 3720 次点击
    这是一个创建于 1237 天前的主题,其中的信息可能已经有所发展或是发生改变。

    不捕获 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 问题,肯定是有什么地方你没有想到或没设计好,你需要做的是修改代码而不是掩盖错误。

    捕获所有错误你唯一需要付出的代价就是:多敲几个字。而付出的这点代价你将获得:底层成本的设计负担,无脑的心智负担,健壮的代码,严格的输入输出限定。

    12 条回复    2022-07-24 12:46:37 +08:00
    kalista
        1
    kalista  
       2022-07-22 22:11:17 +08:00
    用不用 recover 还是得看场景,对于开发来说,当然希望 panic 被我们感知到比较好,但是有些 to B 产品,甲方是会关注你是否有 panic 的,对于这种,我们需要做到既不 panic (不被甲方知道)同时我们又能知道服务出现过问题,总之就是具体事情具体分析。永远不能脱离业务
    lysS
        2
    lysS  
       2022-07-22 22:15:13 +08:00
    我是这样安慰自己的:总比 C 返回一个 err code 好吧。。。。
    Ricardo5
        3
    Ricardo5  
       2022-07-22 23:34:07 +08:00 via Android
    主要还是太丑了,rust 用模式匹配看起来就美观很多
    messyidea
        4
    messyidea  
       2022-07-23 05:22:17 +08:00 via Android   2
    panic 了整个进程就退出了,web framework 的所有其它并发请求都会失败,而如果 recover ,则不会影响其它并发请求。再说发现程序是否有 panic ,不一定要进程退出,panic 打点metrics 告警也能发现问题
    Aloento
        5
    Aloento  
       2022-07-23 06:10:43 +08:00
    总之就是太丑而且说真的麻烦,错误处理还得看 C#(你甚至都不知道它到底会不会报错)
    dcoder
        6
    dcoder  
       2022-07-23 07:48:55 +08:00
    @Aloento
    "错误处理还得看 C#(你甚至都不知道它到底会不会报错)"
    LOL 这是黑还是夸 C# ?
    tqyq88
        7
    tqyq88  
       2022-07-23 08:16:07 +08:00
    判断 err != nil 才是恶心的根源
    2828kakafa
        8
    2828kakafa  
       2022-07-23 15:18:39 +08:00 via iPhone
    你捕获了又能怎么样呢,你能写出绝对完美的程序?自欺欺人,不如直接忽略掉,在重要的地方捕获 err 或者打日志,只有妥协,才能走的更快
    mmdsun
        9
    mmdsun  
       2022-07-24 01:15:22 +08:00 via iPhone
    @dcoder 可能说的是 C#异常不像 Java 那样必须 try catch 捕获,不然编译不过? 反正 Java 检查性异常满屏的 try catch ,看起来也十分不雅,我会用 lombok 插件来处理这种情况。
    Aloento
        10
    Aloento  
       2022-07-24 01:18:30 +08:00
    @dcoder 只是在说对 C#的无奈
    很多情况下如果写库的人不在注释里面标注要报什么错,我都不知道要不要 try 它
    只有真出了问题才知道要 try
    iosyyy
        11
    iosyyy  
       2022-07-24 09:23:04 +08:00
    @mmdsun java 很多时候套个 aop 就直接抛就行了..统一做处理就可以了
    buffzty
        12
    buffzty  
       2022-07-24 12:46:37 +08:00
    绝大多数觉得 go 语言错误处理不好的都是菜逼. 因为 go 的错误处理跟 c 语言是一样的,而且比 c 语言好.
    并且 go 是有 try catch 模式的(不是 recover 那种) 每次看见一群菜鸟喷 err 错误处理就想笑 咋没人喷 c 的错误处理?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4471 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 38ms UTC 09:47 PVG 17:47 LAX 01:47 JFK 04:47
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86