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

Go 社区否决了新的 try 语句提议

  •  1
     
  •   SsuchingYu ·
    SiqingYu · 2019-07-17 10:08:43 +08:00 · 10929 次点击
    这是一个创建于 1960 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Proposal: A built-in Go error check function, "try" · Issue #32437 · golang/go https://github.com/golang/go/issues/32437

    76 条回复    2019-07-23 13:34:35 +08:00
    SsuchingYu
        1
    SsuchingYu  
    OP
       2019-07-17 10:17:18 +08:00
    jinliming2
        2
    jinliming2  
       2019-07-17 10:21:09 +08:00 via iPhone   ❤️ 1
    我也觉得,如果单纯是语法糖的话,旧语法和新语法间可以完全相互转换的话,没有必要。
    rrfeng
        3
    rrfeng  
       2019-07-17 10:32:55 +08:00
    刚好前几天看了眼,感觉 try 根本就没解决问题,只是看起来 /写起来稍微简单了点,所以被拒是正常的。
    kidlj
        4
    kidlj  
       2019-07-17 10:33:45 +08:00   ❤️ 2
    其实 try() 不是真正的 error _handling_,只是检查 err != nil 并直接返回,Griesemer 的 tryhard 工具也验证了在现有代码库里能应用到的地方很有限,为了这一点点便利而引入一种新的写法不值得。

    我认为当前 if err != nil 的模式肯定有可以改进的地方,但肯定不是 try(),所以很高兴这个提案被撤回了。
    dbskcnc
        5
    dbskcnc  
       2019-07-17 10:34:37 +08:00   ❤️ 1
    这个好, 虽然 if err!=nil 是有点啰嗦,但是对于程序稳定性真的非常好
    flowfire
        6
    flowfire  
       2019-07-17 10:37:57 +08:00
    @jinliming2 #2
    @rrfeng #3

    语法糖为什么没有必要。。。
    async await 就是 Promise+Generator 的语法糖啊。。。
    能节省开发效率当然是好事。。。
    janxin
        7
    janxin  
       2019-07-17 10:41:47 +08:00
    否决不是坏事,起码社区力量的展示吧。
    Hellert
        8
    Hellert  
       2019-07-17 10:42:30 +08:00
    要解决就一次性永久解决,别搞什么中间方案,支持否决。
    ruyuejun
        9
    ruyuejun  
       2019-07-17 10:45:04 +08:00   ❤️ 2
    非常 nice。
    没有对写法造成根本性的改变的语法糖,我认为是不必要的。
    相应的,js 的 async await 语法糖带来的是颠覆式的书写风格,利远大于弊,当然觉得很好,而 go 中的 try 不但没有根治异常处理,还带来了恶心的函数嵌套。
    我理解的是 Go 社区不应该过分坚持简单、单一哲学,坚持没错,但是这个地方如此沉重,和泛型一样,应该有大刀阔斧的改革勇气
    boboliu
        10
    boboliu  
       2019-07-17 10:46:28 +08:00
    这个 try 函数作为语法糖的意义确实很低…… go 目前的关键字和内置函数很克制,个人认为加这样一个隐藏细节且对程序稳定性没有好处的谜之语法糖并没有使 go 的 error handle 更友好的效果。
    rrfeng
        11
    rrfeng  
       2019-07-17 10:51:28 +08:00   ❤️ 1
    @flowfire
    async await 收益巨大,傻子也能写异步了。promise 真的太难了。
    try 相比之下收益太小了,错误处理还是要写,只能包一个 func (这点真的很蠢……),而且现在很多 MustFunc 写法。总之看起来就不是个好的解决方案,况且它没解决根本问题。
    janxin
        12
    janxin  
       2019-07-17 10:52:34 +08:00
    try(try(try(try(try(try(try(try(try(try(f()))))))))))

    你要是敢让人这么写,就一定会有人这么写。实际上我是支持解决 error hanling 问题,但是 built-in try 函数方案,就是不行...其实我倒是觉得引入 Rust 的?可以,不过大佬们觉得麻烦不是,我觉得这个事情社区可以再推一推
    Rorysky
        13
    Rorysky  
       2019-07-17 11:05:47 +08:00 via iPhone
    @flowfire go 的事情 能和 ecmascript 一样么?
    x7395759
        14
    x7395759  
       2019-07-17 11:09:21 +08:00
    支持!
    wysnylc
        15
    wysnylc  
       2019-07-17 11:09:52 +08:00
    @janxin #12 只存在不用和滥用,不滥用是不可能的
    qq976739120
        16
    qq976739120  
       2019-07-17 11:14:34 +08:00
    try 这样的语法糖,第三方实现的很多了,喜欢的早用上了,算啥改进啊
    luoyou1014
        17
    luoyou1014  
       2019-07-17 11:14:54 +08:00
    @janxin rust 的也很麻烦的,match match match unwrap unwrap 顺带 Some 里面的内容可能是引用的,处理起来就是一个字,烦。
    ChristopherWu
        18
    ChristopherWu  
       2019-07-17 11:26:29 +08:00
    @qq976739120 go 没有宏,怎么做语法糖?包个函数做法太奇怪了。
    ChristopherWu
        19
    ChristopherWu  
       2019-07-17 11:27:00 +08:00
    @dbskcnc 跟异常比起来,哪里对稳定性好?
    petelin
        20
    petelin  
       2019-07-17 11:28:50 +08:00 via iPhone
    有什么好 try 的
    错误都不处理 还想写出来好软件
    mcfog
        21
    mcfog  
       2019-07-17 11:34:47 +08:00
    @rrfeng 能用 promise 把异步写清楚的人也许十个里面只有两三个,能用 async-await 写清楚的可能就只有半个,来源于我面试下来的主观感受
    qq976739120
        22
    qq976739120  
       2019-07-17 11:43:15 +08:00
    @ChristopherWu https://github.com/manucorporat/try . 类似这样的,我随手搜了个,应该有更完善的
    ChristopherWu
        23
    ChristopherWu  
       2019-07-17 11:49:01 +08:00
    @qq976739120 所以都要传 lambda 过去,很奇怪的。
    fatedier
        24
    fatedier  
       2019-07-17 11:52:15 +08:00
    感觉 "if err != nil " 问题不大, 并不是迫切的需求,泛型才是。
    hst001
        25
    hst001  
       2019-07-17 11:52:36 +08:00
    try 还是没解决 if err != nil 啰嗦的问题
    fengjianxinghun
        26
    fengjianxinghun  
       2019-07-17 11:56:40 +08:00   ❤️ 1
    @dbskcnc 好个毛线,标准库内部都偷偷 panic/recover 来当异常用。假如 err 这么好,为什么还用这种自己不推荐,内部偷偷用的玩意?
    blless
        27
    blless  
       2019-07-17 12:09:14 +08:00 via Android
    err 唯一不好用就是没有输出堆栈,return 什么的根本不是问题,代码扫描检查 error 有没有处理就很简单,只要正常处理基本不会崩溃
    BBCCBB
        28
    BBCCBB  
       2019-07-17 12:17:27 +08:00
    这个 try 是真丑
    cubecube
        29
    cubecube  
       2019-07-17 12:21:35 +08:00 via Android
    按理说 go 的程序和库都是基于源码的,不用考虑二进制兼容性,优化语言不算太麻烦的,还是那帮人太偏执。
    polebug
        30
    polebug  
       2019-07-17 13:03:47 +08:00
    支持!
    不喜欢 try 写 if 更自由
    wweir
        31
    wweir  
       2019-07-17 13:08:35 +08:00 via Android
    喜欢 rust 的 err handling 方式
    xfriday
        32
    xfriday  
       2019-07-17 13:18:54 +08:00
    @wweir rust 的 match err 和 if err 有啥区别?还不是通过返回值
    wweir
        33
    wweir  
       2019-07-17 13:50:33 +08:00   ❤️ 4
    @xfriday rust 有 '?' 这个 bug 级语法糖。

    go 代码里面,最多的 err 处理方式,也就是直接抛给上级,而这个刚好 '?' 可以解决。
    有了这个,多了不敢说,60% 的 if err != nil 还是可以消除的。
    并且可以很爽的玩起链式调用了,目前随便来个 err 处理,就会打断链式调用
    loading
        34
    loading  
       2019-07-17 13:51:51 +08:00 via Android
    个人觉得 go 没必要用语法糖。
    allgy
        35
    allgy  
       2019-07-17 14:24:28 +08:00
    if err != nil 够用
    dbskcnc
        36
    dbskcnc  
       2019-07-17 15:01:20 +08:00
    @ChristopherWu 返回值通常都得考虑,这样思维强制必须处理错误,不容易出现那种出错了还往下走的情形
    dbskcnc
        37
    dbskcnc  
       2019-07-17 15:03:16 +08:00
    @fengjianxinghun 这个就是见仁见智而已, 不喜欢也正常,或许 rust 那样的适合您的口味
    ChristopherWu
        38
    ChristopherWu  
       2019-07-17 15:08:28 +08:00
    @fengjianxinghun 这个喷的好。。求标准库源码做例子,观摩观摩。
    ChristopherWu
        39
    ChristopherWu  
       2019-07-17 15:10:55 +08:00
    @dbskcnc 异常不也是一样要考虑?这不算优点。
    dbskcnc
        40
    dbskcnc  
       2019-07-17 15:14:23 +08:00
    @ChristopherWu 出异常的地方通常都跟处理的地方离远了,思维不连续,并且异常容易混一起,也让人很容易偷懒
    neoblackcap
        41
    neoblackcap  
       2019-07-17 15:21:07 +08:00   ❤️ 4
    @xfriday rust 里面是学习 haskell 的 monad,除非你是消费以及最终求值的阶段,否则不会有人会去用 match 来处理错误。
    rust 的错误处理最大的优势就是,之前步骤的异常,并不会影响你的业务逻辑,以及强制错误处理。你完全可以使用 and_then 或者 map 方法对一个 Result 进行结果转换,完全不用什么 match。?只是一个相对简洁的语法糖,就算不用 rust 也比现有的什么异常以及返回值优秀。
    当然你不了解 monad,强制每一步都 match 一下,那就认为 rust 也是返回值吧。毕竟宝马跟单车都是靠轮子走的,而且都是圆的。
    fengjianxinghun
        42
    fengjianxinghun  
       2019-07-17 15:29:16 +08:00
    @ChristopherWu


    ```
    // Serve a new connection.
    func (c *conn) serve(ctx context.Context) {
    c.remoteAddr = c.rwc.RemoteAddr().String()
    ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr())
    defer func() {
    if err := recover(); err != nil && err != ErrAbortHandler {
    const size = 64 << 10
    buf := make([]byte, size)
    buf = buf[:runtime.Stack(buf, false)]
    c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)
    }
    if !c.hijacked() {
    c.close()
    c.setState(c.rwc, StateClosed)
    }
    }()
    ```

    err 真这么好干嘛到处 recover ?
    fengjianxinghun
        43
    fengjianxinghun  
       2019-07-17 15:30:37 +08:00
    h__t__t__p__s:\\golang.org\src\net\http\server.go

    冒失没有手机号不让发 url


    // Serve a new connection.
    ```
    func (c *conn) serve(ctx context.Context) {
    c.remoteAddr = c.rwc.RemoteAddr().String()
    ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr())
    defer func() {
    if err := recover(); err != nil && err != ErrAbortHandler {
    const size = 64 << 10
    buf := make([]byte, size)
    buf = buf[:runtime.Stack(buf, false)]
    c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)
    }
    if !c.hijacked() {
    c.close()
    c.setState(c.rwc, StateClosed)
    }
    }()
    ```
    rrfeng
        44
    rrfeng  
       2019-07-17 15:37:15 +08:00
    @mcfog
    我觉得能写好 promise 的人一定能用 async/await,但是不会用 async/await 的肯定 promise 也不懂。
    而且还有 async 属于新标准,很多人不一定知道并且用过……
    karllynn
        45
    karllynn  
       2019-07-17 15:37:24 +08:00
    xerrors 可以输出栈了,所以都还好…泛型比较重要一些
    liuguang
        46
    liuguang  
       2019-07-17 15:38:58 +08:00
    这个就是多返回值语言的优点,明明可以直接 return 多方便,try catch 和 defer 一样,只会让程序变得更慢。
    defer 为了关闭资源还可以理解,而明明知道有 error,不直接处理,还在一堆代码里面 catch,不如直接 return 来的高效。
    fengjianxinghun
        47
    fengjianxinghun  
       2019-07-17 15:49:47 +08:00
    @liuguang go 现在的多返回值实现是用栈来实现的,没办法像 c/c++用 rax 返回,速度慢了一大截。
    dbskcnc
        48
    dbskcnc  
       2019-07-17 15:56:09 +08:00
    @fengjianxinghun err 或者 panic 都可以用,个人是喜欢 err, 但是有人喜欢用 panic,你也没办法,毕竟这里没有对错,只是风格喜好不同, 如果你调用的模块(库)用了 panic,只有 recover 应对, 自己写的几年 go 没用过 panic,但 recover 有时还是得用
    mcfog
        49
    mcfog  
       2019-07-17 16:06:53 +08:00 via Android
    @rrfeng 所以说我观察下来就是能写写 promise 但一换 async await 就不行了的人挺多的。反过来 async await 写的好的,换 promise 也能写,就是幸福指数下降罢了,也就是说 async await 带来的字面上的简单让不少人误以为自己能轻松把异步代码写好了(然而并不)

    我觉得 golang 关于语法糖的思路也是有这种拒绝虚假的幸福指数的倾向,不做让复杂的事情(异步/错误处理)表面上变简单,但并不降低实际复杂度的语法糖
    xfriday
        50
    xfriday  
       2019-07-17 16:07:08 +08:00
    @neoblackcap 我认为就是 fp 那一套而已,本身没有区别,各种 or_else, map_err 我是没有看出什么优雅来,如果没有编译器优化,甚至效率都低下
    xfriday
        51
    xfriday  
       2019-07-17 16:15:09 +08:00
    clear is better than clever,越是复杂的东西,推广和维护成本就越高,foo("".into()),我特么找个实现要到处去翻
    ChristopherWu
        52
    ChristopherWu  
       2019-07-17 16:19:00 +08:00
    @xfriday 本来编译器的目标之一就是优化- = -
    bobuick
        53
    bobuick  
       2019-07-17 16:20:39 +08:00
    try catch 没什么卵用. 用 go 写 crud 的会感觉 try 必要性比较大, 用 go 写偏系统一点的东西, try 基本上没卵用了.
    xfriday
        54
    xfriday  
       2019-07-17 16:20:48 +08:00
    rust 宣称的无数据竞争,仅仅是靠不可变来实现,这叫解决问题吗?根本就是回避问题,如果确实需要多线程共享变量,到头来还是要靠锁,rust 会打广告是真的
    fengjianxinghun
        55
    fengjianxinghun  
       2019-07-17 16:39:16 +08:00
    @bobuick 别吹,go 标准库是偏系统没有 crud 吧?里面也一堆 panic/recover 当 try catch 用
    TheBestSivir
        56
    TheBestSivir  
       2019-07-17 18:31:40 +08:00
    @xfriday 不可变对象就是解决的数据竞争,代码如果是 immutable 风格的就是天然不存在并发问题的。至于线程间数据共享你认为还要上锁,是因为你用了 immutable 的 rust 写出了 java/c++的代码,不可变对象是通过 copy on read/write 来解决并发问题的。理论上不存在两个线程共享一个引用的问题
    xfriday
        57
    xfriday  
       2019-07-17 18:45:07 +08:00
    @TheBestSivir Mutex,Arc、Rc、RefCell 是什么?什么叫“理论上不存在两个线程共享一个引用的问题“?真以为 rust 的 ownership 能解决所有问题?
    secondwtq
        58
    secondwtq  
       2019-07-17 18:57:11 +08:00 via iPad
    async/await 是帮你做 CPS,这个是有一定复杂性的,已经超过了语法糖的范畴了。
    morethansean
        59
    morethansean  
       2019-07-17 18:58:09 +08:00
    @mcfog 你确定吗……反正我遇到的真实业务里能用 promise 写清楚一个稍微复杂点逻辑的比 aa 少多了……虽然不深入了解 promise 的人对 aa 也就停留在最简单的使用上,但至少他们能用这个写出代码……
    secondwtq
        60
    secondwtq  
       2019-07-17 19:12:04 +08:00 via iPad
    另外我倒是认为这个没必要关注也没必要吵,因为用 Go 的其实并不关注这些东西,关注这些东西的不用 Go。吵半天一点意义都没有
    mcfog
        61
    mcfog  
       2019-07-17 19:31:17 +08:00
    @morethansean 写一些简单的并发和错误处理,面试过程中可能是本能以为 async/await 简单,会有人准备要用,然而最终很少有人能写出来,基本都要让他们回到用 promise 的路上

    哦,如果你是说用 await 把所有的并发都变成串行也算是写出代码的话,那可能是 async/await 更容易让人写出代码
    morethansean
        62
    morethansean  
       2019-07-17 19:35:36 +08:00
    @mcfog #61
    为什么要把并发改写成串行?不明白你的逻辑。从使用成本上,promise 比 aa 高是很明显的事实。
    secondwtq
        63
    secondwtq  
       2019-07-17 19:41:23 +08:00 via iPad
    @neoblackcap 老哥受了什么刺激,为什么要对牛谈琴呢

    @mcfog 我不知道你所谓的”用 async-await 写清楚”是什么意思,但是很明显的 Promise 和 async-await 不是替代关系,从能力上来说 async-await 还要比你 Promise 弱,只用 async-await 写逻辑当然是无法做到的
    momo733
        64
    momo733  
       2019-07-17 19:48:27 +08:00 via iPhone
    昨天刚投了反对票,宁愿用现在也不想要这个 try
    trait
        65
    trait  
       2019-07-17 19:51:47 +08:00 via iPhone
    @xfriday 废话,rust 本来就是函数式近亲属,部分特性都是从 Haskell 弄过来的
    neoblackcap
        66
    neoblackcap  
       2019-07-17 20:20:20 +08:00
    @secondwtq 我只是发了一次言,其实还好。我只是说明一下这东西的优势在哪里,为什么 Monad 是更好的异常处理而且。毕竟一次回复不仅仅是一个人看到。大家也可以看到。大家各取所需,觉得 golang 好的就继续写,觉得其他更好的就去写其他就好了。我觉得没什么必要纠结什么天下第一,毕竟电锯跟锤子不一样,CNC 机床也不能替代凿子。当然爱一样东西,自己能出力去让它变得更好,这样也不错。
    lazyfighter
        67
    lazyfighter  
       2019-07-17 21:14:28 +08:00
    我最不能理解的是变量在左类型在右,我是真特么别扭
    lazyfighter
        68
    lazyfighter  
       2019-07-17 21:14:58 +08:00
    还有一个接口的实现,不指定接口,需要参数类型相同,真尼玛傻吊
    yegle
        69
    yegle  
       2019-07-18 02:01:11 +08:00
    @janxin

    try(try(try(try(try(try(try(try(try(try(f()))))))))))


    除非 f 的返回类型是 val, err, err, err, err, err, err, err,这个时候更应该关注的的是写 f()的人而不是 try()这个语法糖

    更有意义的例子应该是

    foo(try(bar(try(baz()))))
    abscon
        70
    abscon  
       2019-07-18 10:41:14 +08:00
    @xfriday
    你的话题从错误处理转进到多线程编程了。
    我可以理解为你已经承认了自己在错误处理上对于 Rust 的错误认识么?
    毕竟已经不正面回应,而是开始转到下一个话题了。
    xfriday
        71
    xfriday  
       2019-07-18 14:09:33 +08:00
    @abscon 我想表达的不是你说的意思,而是看不惯 rust 吹,至于错误处理,err,exception,monad 没有哪个有绝对优势,但是 rust 粉的说话方式总是居高临下
    xfriday
        72
    xfriday  
       2019-07-18 14:10:21 +08:00
    也不清楚你的第二句话是根据何种理论得出的
    perfectlaugh
        73
    perfectlaugh  
       2019-07-18 15:08:07 +08:00
    我只知道我用 rust 唯一不满的是还没有 stable async 和 windows mio
    perfectlaugh
        74
    perfectlaugh  
       2019-07-18 15:10:26 +08:00
    而且 rust 和 go 走的道路本身就不一样 有不同的情景可以用不同的工具 不好🐎?
    reus
        75
    reus  
       2019-07-23 13:31:57 +08:00
    @fengjianxinghun https://github.com/golang/go/wiki/PanicAndRecover wiki 里都教你怎么用了,自己不知道,就说“偷偷”,呵呵。
    reus
        76
    reus  
       2019-07-23 13:34:35 +08:00
    @fengjianxinghun 这里用 recover 有什么问题?如果代码有 bug,例如 slice 越界,recover 就可以保证其他连接不受影响。panic / recover 本来就是这样用的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1064 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 19:47 · PVG 03:47 · LAX 11:47 · JFK 14:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.