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 · 3295 次点击
    这是一个创建于 855 天前的主题,其中的信息可能已经有所发展或是发生改变。

    不捕获 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 才是恶心的根源
    lidage
        8
    lidage  
       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   ·   实用小工具   ·   1320 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 17:54 · PVG 01:54 · LAX 09:54 · JFK 12:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.