写了个 err warp,或许可以少写点 if err - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
voidmnwzp
V2EX    Go 编程语言

写了个 err warp,或许可以少写点 if er

  •  
  •   voidmnwzp
    NullpointerW 2023-04-28 15:43:39 +08:00 4678 次点击
    这是一个创建于 927 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一般情况下需要串行化的执行下去,如果其中一步遇到错误就会退出,但这样调用完个每个方法都要写个 err

    png

    如果将执行的方法作为一个闭包封装进去,就可以省去一大堆 if err:

    png

    这样如果执行的过程中遇到了错误,也会跳过执行, 最后调用 wrap.Error()返回错误 e.g.:

    png

    外层变量 a,b,c,d 可以通过闭包来赋值

    47 条回复    2023-05-26 02:06:48 +08:00
    rrfeng
        1
    rrfeng  
       2023-04-28 15:46:28 +08:00
    没变少啊……
    chanyan
        2
    chanyan  
       2023-04-28 15:47:23 +08:00
    sduoduo233
        3
    sduoduo233  
       2023-04-28 15:49:07 +08:00 via Android
    这样怎么确定 err 是在哪一步抛出的?
    learningman
        4
    learningman  
       2023-04-28 17:17:14 +08:00 via Android
    你这写的比 if err 还多
    ljsh093
        5
    ljsh093  
       2023-04-28 17:20:35 +08:00
    还是 4 行一个啊
    777777
        6
    777777  
       2023-04-28 17:24:07 +08:00   10
    就我一个人喜欢写 if err ?简单直接
    blackvv666
        7
    blackvv666  
       2023-04-28 17:26:57 +08:00
    自己用用可以
    hahasong
        8
    hahasong  
       2023-04-28 17:31:35 +08:00
    这还不如用 defer 呢 有种用 java 面向对象打印 hello world 即视感
    hzzhzzdogee
        9
    hzzhzzdogee  
       2023-04-28 17:41:11 +08:00
    其实应该是 wrap?
    zhangxh1023
        10
    zhangxh1023  
       2023-04-28 17:47:30 +08:00   2
    没了 if err 的 golang 都没那味儿了
    helloit
        11
    helloit  
       2023-04-28 17:49:49 +08:00
    errors := map[string]string{
    "a": "a error",
    "b": "b error",
    "c": "c error",
    "d": "d error"
    }
    magicdawn
        12
    magicdawn  
       2023-04-28 17:50:21 +08:00 via Android
    rust 也是 err value ,但是有 unwrap 和 ?存在方便许多
    fgwmlhdkkkw
        13
    fgwmlhdkkkw  
       2023-04-28 17:51:26 +08:00
    ```

    func Must[T any](T val, e error) T {
    if e != nil {
    painc(e)
    }
    rturn val
    }


    func Must2[T any, K any](T val1, K val2, e error) (T, K) {
    if e != nil {
    painc(e)
    }
    return val1, val2
    }


    ```
    fgwmlhdkkkw
        14
    fgwmlhdkkkw  
       2023-04-28 17:52:52 +08:00
    @fgwmlhdkkkw 哈哈哈哈,,搞混了
    cassyfar
        15
    cassyfar  
       2023-04-28 17:54:33 +08:00
    人才
    6ufq0VLZn0DDkL80
        16
    6ufq0VLZn0DDkL80  
       2023-04-28 17:55:20 +08:00   2
    你重新发明了那篇经典的 errors are values 博文中建议的实践。

    https://go.dev/blog/errors-are-values
    Leviathann
        17
    Leviathann  
       2023-04-28 18:10:49 +08:00
    @magicdawn rust 是 value or error 不是 value and error
    TWorldIsNButThis
        18
    TWorldIsNButThis  
       2023-04-28 18:16:51 +08:00
    @cholerae
    这篇经典博文也不过是在重新发明 result/either monad
    也许这就是一种传承
    dobelee
        19
    dobelee  
       2023-04-28 18:24:03 +08:00
    一行没变少,反而增加几行初始化变量。。
    voidmnwzp
        20
    voidmnwzp  
    OP
       2023-04-28 18:25:41 +08:00 via iPhone
    @cholerae 不瞒你说 我就是看了 rob pike 写的 wrap 后才写的
    MIUIOS
        21
    MIUIOS  
       2023-04-28 18:27:23 +08:00
    与其叫少写,不如叫遮羞布。。。
    lesismal
        22
    lesismal  
       2023-04-28 18:27:44 +08:00   1
    @777777 #6 你不是一个人!喜欢 if err 的人多着呢,只是我都懒得喷那些喷 if err 的人罢了
    voidmnwzp
        23
    voidmnwzp  
    OP
       2023-04-28 18:36:28 +08:00 via iPhone
    elechi
        24
    elechi  
       2023-04-28 18:46:20 +08:00
    好像有个 multierr 包
    RedisMasterNode
        25
    RedisMasterNode  
       2023-04-28 20:35:29 +08:00
    觉得 if err != nil 让别人更容易搞懂程序每一步的错误想怎么处理...不明白为何要把它 warp 或者简化起来
    mogita
        26
    mogita  
       2023-04-28 20:39:36 +08:00
    字面意义上的过度封装。
    flyqie
        27
    flyqie  
       2023-04-28 21:02:47 +08:00
    hsfzxjy
        28/div>
    hsfzxjy  
       2023-04-28 21:05:26 +08:00 via Android
    虽然但是,为什么是 warp 不是 wrap
    cmdOptionKana
        29
    cmdOptionKana  
       2023-04-28 21:14:19 +08:00
    我也有做类似的处理

    // WrapErrors 把多个错误合并为一个错误.
    func WrapErrors(allErrors ...error) (wrapped error) {
    for _, err := range allErrors {
    if err != nil {
    if wrapped == nil {
    wrapped = err
    } else {
    wrapped = fmt.Errorf("%w | %w", wrapped, err)
    }
    }
    }
    return
    }
    cmdOptionKana
        30
    cmdOptionKana  
       2023-04-28 21:16:46 +08:00
    我这个使用时应该更直白简洁, 例如

    a, err1 := func1()
    b, err2 := func2()

    if err := WrapErrors(err1, err2); err != nil { return err }
    zbinlin
        31
    zbinlin  
       2023-04-28 21:40:33 +08:00   1
    这时候不应该换语言了吗
    SenLief
        32
    SenLief  
       2023-04-28 22:06:19 +08:00   1
    if err 都没有,那还是 go 了吗?
    piaodazhu
        33
    piaodazhu  
       2023-04-28 22:26:57 +08:00
    想到个这个,大家看这样有什么问题不:
    1. 定义一个函数 func checkError(err error),函数内检查如果 err!=nil 就 panic(err)
    2. 在你业务函数开头写一个 defer func()内部做 recover()
    3. 在你业务函数中每次调用后,调用 checkError(err)

    这样就不用写那么多`if err != nil { ... `了吧,panic 被捕获时,也能知道发生 err 的是啥。
    yazinnnn
        34
    yazinnnn  
       2023-04-28 23:02:45 +08:00 via Android   2
    是我第 2887 喜欢的 go boy 重新发明 monad 时间
    Kisesy"
        35
    Kisesy  
       2023-04-28 23:08:13 +08:00
    @cmdOptionKana 楼主要的效果是,有函数有错误,下面的代码就不执行了,你这个即使 func1 出错了,func2 还是会执行
    voidmnwzp
        36
    voidmnwzp  
    OP
       2023-04-28 23:31:36 +08:00
    @piaodazhu 可以是可以 这样就是类似 java 的 try/catch 但是,风险太大 万一哪个地方漏写了 recover 那不是单个 goruntine down 了 是个整个进程都得挂 一不小心就是线上重大事故了属于
    voidmnwzp
        37
    voidmnwzp  
    OP
       2023-04-29 00:00:54 +08:00 via iPhone
    @hsfzxjy 因为我拼错了。z
    yrj
        38
    yrj  
       2023-04-29 05:45:16 +08:00
    @voidmnwzp 没事,我也经常拼错
    Nasei
        39
    Nasei  
       2023-04-29 09:21:20 +08:00
    @magicdawn 如果不用库,rust 的 ? 在 Err 类型不一样的时候感觉很难受....
    magicdawn
        40
    magicdawn  
       2023-04-29 17:21:49 +08:00
    @Nasei

    有编译器语法糖啊, Result<>? / Option<>? 会自动 check 是否是 err / 是否有值
    不用库啊, go 可以学一下.
    magicdawn
        41
    magicdawn  
       2023-04-29 17:43:06 +08:00
    @Nasei map_err / ok_or_else 啊
    magicdawn
        42
    magicdawn  
       2023-04-29 17:47:10 +08:00
    @Nasei

    类型不一样这个...再怎么难受也比 go 机械地写 if err != nil 好吧, 本该是编译器做的事情却让开发者承担.
    voidmnwzp
        43
    voidmnwzp  
    OP
       2023-04-29 18:12:32 +08:00 via iPhone   1
    @magicdawn go2 会有语法糖的
    比如
    usr:=getUser
    handle err{
    return user{}
    }
    fregie
        44
    fregie  
       2023-04-30 10:12:11 +08:00 via Android
    golang 都迭了这么多代了,仍然一点没改错误处理机制,大概谷歌那帮开发 golang 的专家没有这里的评论者考虑的周全吧,为什么不加 try-catch 呢?
    从对 golang 的理解就可以看出各位到底是一位优秀的 coder 还是一位优秀的 engineer
    coder 会从自己的角度出发,觉得写起来最方便最快的就是好的
    engineer 会从工程的角度出发,考虑如何能让工程的效率和质量更好
    现代大型软件的业务逻辑 bug ,绝大多数都是因为错误处理不得当导致的,各位 coder 不妨回想一下最近一年遇到的 bug ,是不是如此。
    这种又臭又长的错误处理机制,虽然烦人,但是有效
    fregie
        45
    fregie  
       2023-04-30 10:14:36 +08:00 via Android
    @voidmnwzp 我打赌没有,有这种语法糖 go 就废了
    voidmnwzp
        46
    voidmnwzp  
    OP
       2023-04-30 15:17:12 +08:00 via iPhone
    @fregie 我认为 error is value 的设计并无不妥 只是实际业务中每一个 err 都需要去 if err 处理 太麻烦 不处理万一出现问题 那是找死都找不出来的
    ireina
        47
    ireina  
       2023-05-26 02:06:48 +08:00
    我也尝试过类似的事。我觉得没必要去改`if err != nil`其实,错误处理是一种计算效应,真正的干净的代码需要 monad ,但是目前没几个语言直接支持 monad 的上下文管理。把 error wrap 起来的确是一种处理错误的方式,标准库里其实也有使用过(但是很少),这种方式的缺点在于你必须很清楚 error 的状态是如何共享的。我觉得在给 interface 写 adapter 的时候可以用,但是平时写 struct 是不必要的。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1071 人在线 &nsp; 最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 23:10 PVG 07:10 LAX 15:10 JFK 18:10
    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