想为 golang 添加一个错误处理语法糖 !err, 大家来看看这种错误处理方式如何 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
sofukwird
V2EX    Go 编程语言

想为 golang 添加一个错误处理语法糖 !err, 大家来看看这种错误处理方式如何

  •  
  •   sofukwird 2023-08-31 08:01:18 +08:00 4769 次点击
    这是一个创建于 846 天前的主题,其中的信息可能已经有所发展或是发生改变。

    简介

    这是一个为 Go 添加 !err 错误处理语法糖的项目, 与 Go 完全兼容(毕竟只是语法糖)

    有了它你可以写如下代码, 代码更加紧凑 阅读更轻松

    转换前:

    package main import ( "fmt" "os" ) func main() { body, !err := readSelf() fmt.Println("main.go content") fmt.Println(body) } func readSelf() (content string, err error) { body, !err := os.ReadFile("main.go") cOntent= string(body) return } 

    转换后:

    package main import ( "fmt" "os" ) func main() { body, err := readSelf() if err != nil { return } fmt.Println("main.go content") fmt.Println(body) } func readSelf() (content string, err error) { body, err := os.ReadFile("main.go") if err != nil { return } cOntent= string(body) return } 

    项目地址: https://github.com/gone-lang/gone

    先来问问各位大佬的意见, 看下怎么做比较好

    第 1 条附言    2023-08-31 09:00:36 +08:00

    打印错误日志.

    func readSelf() (content string, err error) { defer func() { if err == nil { return } slog.Error("wrong", "err", err) }() body, ierr := os.ReadFile("main.go") cOntent= string(body) return } 

    如果需要立即处理错误, 可以不使用语法糖使用原有的 if err != nil {} 模式.
    语法糖是可以随时退出不使用的

    36 条回复    2023-09-01 09:41:32 +08:00
    AKAUP
        1
    AKAUP  
       2023-08-31 08:19:24 +08:00   1
    照你的方法,如果在报错的想打印日志应该怎么做呢,比如:
    ```
    if err != nil {
    logger.Error("something wrong")
    return err
    }
    ```
    morri
        2
    morri  
       2023-08-31 08:24:56 +08:00
    个人感觉其实 没必要每个错误都去处理,关键点判断好,单元测试写好,应该就可以了。

    例如

    var u entity.User
    _=dao.User.Ctx(ctx).Scan(&u,"id",uid)

    if u.id==0{
    return fmt.error("user does not exist")
    }

    // 这里直接返回自定义的错误,中间件也好其他处理,比如多语言返回
    rekulas
        3
    rekulas  
       2023-08-31 08:29:50 +08:00
    if err != nil {
    return
    }
    好家伙 返回值都不要了?
    rekulas
        4
    rekulas  
       2023-08-31 08:31:43 +08:00
    @rekulas 看错了 有返回值
    不过仍然感觉不是太好用,有些情况返回 err 但其他返回值可能也有用 意义可能不是很大
    rekulas
        5
    rekulas  
       2023-08-31 08:37:29 +08:00   1
    有个大问题是带来了兼容性问题, 我喜欢 go 的就是一次编码到处运行,如果用这种可能就得变成一次编码到处配置环境..用户下载一份源码,发现还无法编译得单独配置下,妥妥有前些年好压的既视感了,除非官方支持
    sofukwird
        6
    sofukwird  
    OP
       2023-08-31 08:55:43 +08:00
    @AKAUP 使用 defer 打印错误, 如果需要立即处理错误, 可以不是用语法糖使用原有的 `if err != nil {}` 模式. 语法糖是可以随时退出不使用的
    ```go
    func readSelf2() (content string, err error) {
    defer func() {
    slog.Error("wrong", "err", err)
    }()
    body, !err := os.ReadFile("main.go")
    cOntent= string(body)
    return
    }

    ```

    @rekulas 并不会出现兼容性问题, 会另外生成一个转译后 go 文件, 与其他 go 库是无缝操作的, 你可以认为是 typescript 这种
    @morri 其实你这里也是进行了一个错误处理的判断
    lisxour
        7
    lisxour  
       2023-08-31 09:00:54 +08:00   1
    if err != nil { 不带其他逻辑直接 return }

    一个语法糖只为了对这么一个特定场景下少两三行代码,大概率不会给你过的
    proxychains
        8
    proxychains  
       2023-08-31 09:02:05 +08:00
    @morri 头像好评
    cin
        9
    cin  
       2023-08-31 09:08:09 +08:00   4
    sofukwird
        10
    sofukwird  
    OP
       2023-08-31 09:08:26 +08:00
    @lisxour 正是如此, 已经是被拒绝了所以另起炉灶来实现自己的需求
    SingeeKing
        11
    SingeeKing  
    PRO
       2023-08-31 09:12:01 +08:00
    我很好奇附言里是怎么把 !err 打成 ierr 的…… 难道 lz 用的手写输入?
    sofukwird
        12
    sofukwird  
    OP
       2023-08-31 09:12:16 +08:00
    @cin golang 该如何调用 go+ 代码库呢?
    sofukwird
        13
    sofukwird  
    OP
       2023-08-31 09:26:27 +08:00
    @SingeeKing 这个是一个已有的转译实现, 我用了 `ierr` 作为 `!err` 的替代, 但遇到了一些问题, 打断点需要到转译后的文件才能打上, 在开发中还蛮影响思路的, 后面想到了如果做成 golang 超集语言的话就可以打上断点, 于是又起了个仓库准备实现新思路

    已有的转译实现: https://github.com/shynome/err4 , 现在正在用

    (就像前段时间的帖子说的, 每个程序员都有改造语言的冲动, 我也是对 golang error 的错误处理不满意所以就有这么一个个尝试
    lanlanye
        14
    lanlanye  
       2023-08-31 09:28:19 +08:00 via iPhone   4
    真要做的话我觉得 rust 的方式就不错,语句末尾加一个问号。
    githmb
        15
    githmb  
       2023-08-31 10:03:30 +08:00
    Rust:
    let Ok(bar) = foo() else {
    return fuckyou
    }
    ganbuliao
        16
    ganbuliao  
       2023-08-31 10:23:46 +08:00
    按照 go 的 习惯 是不会加新的语法糖的 毕竟 go 写出来的代码 主要是为了 review 的人 看着舒服的
    vchroc
        17
    vchroc  
       2023-08-31 10:25:25 +08:00
    语言肯定朝着越来越好用的方向发展。
    错误处理,目前看比较好用的有两种:
    GOTO:Exception/Panic
    正确错误二元组:Result<T, E>( Rust )

    golang err 绝对不是正确的方向
    neoblackcap
        18
    neoblackcap  
       2023-08-31 10:27:03 +08:00
    @lanlanye 有类型系统兜底呢,不是简单语法改改就能模仿
    fioncat
        19
    fioncat  
       2023-08-31 10:31:05 +08:00
    像 Rust 那样整个?作为语法糖?

    err := handle()
    if err != nil {
    return fmt.Errorf("Handle error: %w", err)
    }

    ===>

    handle()?.Errorf("Handle error")
    mcfog
        20
    mcfog  
       2023-08-31 10:51:30 +08:00
    https://github.com/golang/go/issues/32437 这里有最全的 golang error handle 的意见
    learningman
        21
    learningman  
       2023-08-31 10:53:24 +08:00 via Android
    你这样不如
    v, ? := xxx()
    guonaihong
        22
    guonaihong  
       2023-08-31 11:16:44 +08:00
    现在一堆 ai 辅助编程的插件 感觉收益不是那么明显。copilot 一个回车解决的事情。
    codersdp1
        23
    codersdp1  
       2023-08-31 11:46:19 +08:00
    func readSelf() (string, error) {
    body, err := os.ReadFile("main.go")
    if err != nil {
    return "",err
    }
    cOntent= string(body)
    return content,nil
    }

    这种怎么处理
    PTLin
        24
    PTLin  
       2023-08-31 12:32:03 +08:00
    https://github.com/golang/go/issues?q=label%3Aerror-handling
    看看这些数不清的提案,相信总有一个是比你这个想法优秀且被枪毙了的。
    sofukwird
        25
    sofukwird  
    OP
       2023-08-31 13:09:05 +08:00 via Android
    @codersdp1 #23 这种情况不使用语法糖,直接使用你现在使用的代码,这个糖是有限的,不打算应对所有情况

    @guonaihong 主要还是想阅读的时候更简单轻松,虽然编辑器能补全但代码行数是实打实地变多了

    @fioncat 不选择 v := xxx()? 是因为它假定了最后返回 error ,而且在只返回 error 的情况下可读性并不好,需要看到末尾才知道这行是否可能出错

    xxx()?

    @learningman 不选择 v, ? := xxx() 则是因为转译后需要自己生成 err 临时变量名并返回,临时变量名会千奇百怪的导致可读性下降。那使用 v, ?err := xxx() ?我一开始就是提议的这种后来发现 v, !err := xxx() 这种读性更好。

    我选择这种模式是因为它易于实现,又或者说正是因为它易于实现我才能选择它
    raies
        26
    raies  
       2023-08-31 13:35:56 +08:00
    不如这样

    body := readSelf()?
    mogita
        27
    mogita  
       2023-08-31 13:48:51 +08:00   1
    感觉无糖更方便,因为我已经告诉别人我是 Errlang 开发者了。
    index90
        28
    index90  
       2023-08-31 16:16:28 +08:00
    FP 才是最优解:
    type Result[T any] struct { v T; err error }
    func(r *Result[T]) IfErr(f func(error)) { if r.err != nil {f(err)} }
    func fmap[A, B any](ra Result[A], f f(a) Result[B]) Result[B] {
    if ra.err != nil { return f(ra.v) }
    return Result[B]{err: error}
    }
    liuguang
        29
    liuguang  
       2023-08-31 16:23:48 +08:00
    设计上用元组就是一个大的失误,值和错误不会同时出现。
    而 rust 的枚举就是很好的设计,rust 的问号运算符也是一个好的语法糖。
    mcfog
        30
    mcfog  
       2023-08-31 16:59:48 +08:00
    @liuguang 偶尔会同时出现的,例如读写 socket 、文件可以失败的同时已经成功了一部分

    不过我同意还是支持代数数据类型能解决不少问题
    Mohanson
        31
    Mohanson  
       2023-08-31 18:25:01 +08:00   1
    对于编程语言来说, 除非你有充分的理由, 否则不要加语法糖.

    注: 我觉得这样写很 cool 就不是一个充分的理由.
    mainjzb
        32
    mainjzb  
       2023-08-31 18:46:01 +08:00
    https://github.com/golang/go/issues/62253
    你的想法已经被毙过了
    aduo
        33
    aduo  
       2023-08-31 19:24:53 +08:00
    想法挺好的... 但是没有明确的 return 语句却可能会 return ,有点孩怕, 感觉容易出事故
    sofukwird
        34
    sofukwird  
    OP
       2023-08-31 20:13:46 +08:00 via Android
    @ck65 golang 称为 err-lang 也确实是实至名归,1/5 的代码行数是由 if err != nil {} 提供的
    第一眼看成了 erlang 略过去了

    @mainjzb 拒绝的理由是我们已经拒绝过了这项提案,泛型也是被拒绝过的现在也加上去了。
    正如 issue 里提到的回复:“golang 不会根据各种错误处理提案的喜爱程度对错误处理进行改进,golang 有自己的节奏”

    @aduo panic 也会导致函数提前返回,相对于使用 panic 的错误处理方案 !err 不会有性能损失
    joesonw
        35
    joesonw  
       2023-08-31 22:24:03 +08:00 via iPhone
    最关键的问题是,一般是鼓励 wrap 一下错误,不然你只看到 io 错误,根本不知道是哪里的问题,排查起来头痛。
    mainjzb
        36
    mainjzb  
       2023-09-01 09:41:32 +08:00   1
    我也会拒绝你,你这等于给语言加了一个宏仅仅为了偷懒少写一些代码而已。
    当然 go 的初期设计确实考虑的很简陋,更聪明一点的做法是像 zig 或 rust 那样。
    go error 设计更大的问题是没有保存堆栈。对于仅仅多写一点代码的问题,完全可以用 ide 来自动补充来解决。
    无论是你的设计还是 rust 的设计还是 zig 的设计,还是当前 go 的设计,都不影响阅读代码。 写代码只是为了偷懒,我认为没有完全的必要性添加此项更改。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1245 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 23:51 PVG 07:51 LAX 15:51 JFK 18:51
    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