请问下 go 语言的错误如何处理 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
jlak
V2EX    Go 编程语言

请问下 go 语言的错误如何处理

  •  
  •   jlak 2024-08-07 19:41:19 +08:00 via iPhone 2894 次点击
    这是一个创建于 444 天前的主题,其中的信息可能已经有所发展或是发生改变。
    楼主编程业余爱好者,用的最多的是 JS
    一直想学一款编译型语言,写了几天 Go
    虽然功能能实现 但是在错误处理方面感觉弄的很差
    编码方式基本是写小函数然后组成中函数再组成大函数
    这种编程方式不知道叫什么,使用 go 的话应该学习什么编程方式?
    在体验的这几天里 最难搞的就是错误处理了
    第一次接触这类的错误处理方式
    好像是说每个可能出错的函数需要返回 error 或 nil
    于是我给可能出错的小函数添加了 error 返回值
    于是在中函数里调用这些小函数是不是也需要返回这个 error
    然后大函数里调用到会返回 error 的中函数就需要返回 error 层层传递叠加
    不知道我有没有解释清楚
    25 条回复    2024-08-12 20:27:21 +08:00
    biu7
        1
    biu7  
       2024-08-07 19:45:43 +08:00
    看你当前层需不需要处理这个错误,需要对特定错误做处理的时候就用 is/as 之类的做判断
    povsister
        2
    povsister  
       2024-08-07 19:59:12 +08:00   1
    需要处理就就地处理,不需要处理的就上抛。如果你觉得没有需要你处理的错误。。
    看实际情况吧,举个例子,web 服务,如果业务一路上抛错误,那么到 web server 的 handler 上,它会统一把这个错误处理成 500 Server error ,至于错误内的 stack 信息,完全取决于你自己实现。
    DefoliationM
        3
    DefoliationM  
       2024-08-07 20:01:46 +08:00 via Android
    是的,跟 c 一样,不过 c 一般返回的 int
    kneo
        4
    kneo  
       2024-08-07 20:05:50 +08:00 via Android
    你说的编程方式是自底向上。
    你说的小函数增加错误返回,中函数大函数也要改,没错。没什么办法,习惯就好了。有经验以后你一开始就会给中函数加上错误返回的签名。
    MrVito
        5
    MrVito  
       2024-08-07 20:09:12 +08:00
    难道 js 不是这样做的吗?
    cmdOptionKana
        6
    cmdOptionKana  
       2024-08-07 20:39:22 +08:00
    Go 提供了机会给你认真对待每一个错误,严格来说确实应该认真对待,这样晚上睡觉也踏实一点。

    但是初学者用 panic 偷懒我觉得也没啥问题。用 panic 就不用层层传递了,直接崩。
    bronyakaka
        7
    bronyakaka  
       2024-08-07 20:56:30 +08:00
    go 只能这么处理,准确来说 go 没有设计错误处理机制,被社区内外无数人诟病。不过也有人喜欢这种原始写法就是了。另外 go 的 err 没有堆栈
    akiyamaakira
        8
    akiyamaakira  
       2024-08-07 21:13:34 +08:00   1
    “编码方式基本是写小函数然后组成中函数再组成大函数”

    实际上不仅仅是编程,这是人类解决各种复杂问题的通用方法,十分有效,可以了解一下其原理,思考和开发效率会更高: https://www.modevol.com/episode/cl4zh80o48f2101o3e2iv849s
    lbp0200
        9
    lbp0200  
       2024-08-07 21:31:30 +08:00
    可以参考大多数 Java 程序员的处理方式,吃掉错误,继续运行
    maxwellz
        10
    maxwellz  
       2024-08-07 21:36:56 +08:00
    基本就是层层返回,如果想比较清晰定位错误,就在返回的时候携带一些信息,或者打日志
    jlak
        11
    jlak  
    OP
       2024-08-07 23:05:55 +08:00 via iPhone
    谢谢各位 原来我大致的方向已经是正确的
    看来只能接受繁琐的错误层层传递
    js 转来感觉 1/3 的时间在写 error
    1/3 在写 struct
    B1acKy1in
        12
    B1acKy1in  
       2024-08-08 03:47:15 +08:00
    @jlak 差不多,错误处理被诟病的一大原因就是大量的时间花在了 if err != nil 上了
    ruanimal
        13
    ruanimal  
       2024-08-08 09:27:24 +08:00
    @jlak 大道至简
    guanzhangzhang
        14
    guanzhangzhang  
       2024-08-08 09:33:11 +08:00
    你想想 c 语言的,只能返回值呢
    HFX3389
        15
    HFX3389  
       2024-08-08 09:43:44 +08:00
    if err != nil 当成 try catch 呗
    henix
        16
    henix  
       2024-08-08 12:36:20 +08:00   2
    这是逼迫你更细致的处理错误,在使用异常的语言中,如果要细致处理错误,代码量并不比 Go 这样的小。

    Go 的错误处理思想继承自 C ,有点“程序的性能消耗和代码量成正比”的意思。比如错误不自带堆栈,因为堆栈有性能开销,如果确实需要的话程序员就要手动加,手动加的时候还可以加上更多上下文信息,有时候比异常更好。

    个人认为应该将错误分成两类:意料之外的,属于程序 bug 的,直接 panic ;意料之内的用户输入错误,上游 API 错误,用 error 处理。

    推荐看看这篇 The Error Model: https://joeduffyblog.com/2016/02/07/the-error-model/
    gerefoxing
        17
    gerefoxing  
       2024-08-08 13:11:55 +08:00
    经常有人吐槽 go 这个设计,隔一段时间就能碰见
    yazinnnn0
        18
    yazinnnn0  
       2024-08-08 14:34:18 +08:00
    go 社区刚刚拒绝了所有关于新增错误处理特性的提案



    凑合过呗, 还能离咋地
    zxdstyle
        20
    zxdstyle  
       2024-08-08 17:34:27 +08:00
    个人还是比较喜欢 go 这种错误处理方式的。时刻提醒自己,你写的每行代码都可能出错,就不会有“小函数增加错误返回,中函数大函数也要改”这种情况了
    jlak
        21
    jlak  
    OP
       2024-08-09 00:57:32 +08:00
    这代码写的一半是 err 判断的感觉
    go
    func GetFileName(hash string, sid string) (string, error) {
    apiUrl := Url + "/api/v2/torrents/files"
    data := url.Values{}
    data.Add("hash", hash)
    req, err := http.NewRequest("POST", apiUrl, strings.NewReader(data.Encode()))
    if err != nil {
    return "", fmt.Errorf("创建请求失败: %w", err)
    }
    req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
    req.Header.Set("Cookie", "SID="+sid)

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
    return "", fmt.Errorf("请求失败: %w", err)
    }
    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
    return "", fmt.Errorf("服务器返回错误状态码: %d", resp.StatusCode)
    }

    body, err := io.ReadAll(resp.Body)
    if err != nil {
    return "", fmt.Errorf("读取响应体失败: %w", err)
    }

    var data []Data
    if err := json.Unmarshal(body, &data); err != nil {
    return "", fmt.Errorf("解析 JSON 失败: %w", err)
    }

    if len(data) == 0 {
    return "", fmt.Errorf("未找到文件数据")
    }

    return data[0].Name, nil
    }
    jlak
        22
    jlak  
    OP
       2024-08-09 01:37:17 +08:00
    一个函数内写了 5 个 err 判断,前期真的很麻烦,后期 debug 是真方便。。。
    p1gd0g
        23
    p1gd0g  
       2024-08-09 09:55:07 +08:00
    这可是 errlang ,别挣扎了 /doge
    NathanCyberC
        24
    NathanCyberC  
       2024-08-10 09:20:13 +08:00
    使用 Github copilot 相关 AI 工具,让它帮你写,要求它处理所有错误。
    bunny189
        25
    bunny189  
       2024-08-12 20:27:21 +08:00 via iPhone
    写点小代码我直接 panic……
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2658 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 13:26 PVG 21:26 LAX 06:26 JFK 09:26
    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