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

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

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

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

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

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

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

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



    凑合过呗, 还能离咋地
    zxdstyle
        20
    zxdstyle  
       135 天前
    个人还是比较喜欢 go 这种错误处理方式的。时刻提醒自己,你写的每行代码都可能出错,就不会有“小函数增加错误返回,中函数大函数也要改”这种情况了
    jlak
        21
    jlak  
    OP
       135 天前
    这代码写的一半是 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
       135 天前
    一个函数内写了 5 个 err 判断,前期真的很麻烦,后期 debug 是真方便。。。
    p1gd0g
        23
    p1gd0g  
       135 天前
    这可是 errlang ,别挣扎了 /doge
    NathanCyberC
        24
    NathanCyberC  
       134 天前
    使用 Github copilot 相关 AI 工具,让它帮你写,要求它处理所有错误。
    bunny189
        25
    bunny189  
       131 天前 via iPhone
    写点小代码我直接 panic……
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2537 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 41ms · UTC 05:38 · PVG 13:38 · LAX 21:38 · JFK 00:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.