V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
jlak

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

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

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

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

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

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

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



    凑合过呗, 还能离咋地
    zxdstyle
        20
    zxdstyle  
       Aug 8, 2024
    个人还是比较喜欢 go 这种错误处理方式的。时刻提醒自己,你写的每行代码都可能出错,就不会有“小函数增加错误返回,中函数大函数也要改”这种情况了
    jlak
        21
    jlak  
    OP
       Aug 9, 2024
    这代码写的一半是 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
       Aug 9, 2024
    一个函数内写了 5 个 err 判断,前期真的很麻烦,后期 debug 是真方便。。。
    p1gd0g
        23
    p1gd0g  
       Aug 9, 2024
    这可是 errlang ,别挣扎了 /doge
    NathanCyberC
        24
    NathanCyberC  
       Aug 10, 2024
    使用 Github copilot 相关 AI 工具,让它帮你写,要求它处理所有错误。
    bunny189
        25
    bunny189  
       Aug 12, 2024 via iPhone
    写点小代码我直接 panic……
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2685 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 69ms · UTC 15:57 · PVG 23:57 · LAX 08:57 · JFK 11:57
    ♥ Do have faith in what you're doing.