Proposal: A built-in Go error check function, "try" · Issue #32437 · golang/go https://github.com/golang/go/issues/32437
1
SsuchingYu OP |
2
jinliming2 2019-07-17 10:21:09 +08:00 via iPhone 1
我也觉得,如果单纯是语法糖的话,旧语法和新语法间可以完全相互转换的话,没有必要。
|
3
rrfeng 2019-07-17 10:32:55 +08:00
刚好前几天看了眼,感觉 try 根本就没解决问题,只是看起来 /写起来稍微简单了点,所以被拒是正常的。
|
4
kidlj 2019-07-17 10:33:45 +08:00 2
其实 try() 不是真正的 error _handling_,只是检查 err != nil 并直接返回,Griesemer 的 tryhard 工具也验证了在现有代码库里能应用到的地方很有限,为了这一点点便利而引入一种新的写法不值得。
我认为当前 if err != nil 的模式肯定有可以改进的地方,但肯定不是 try(),所以很高兴这个提案被撤回了。 |
5
dbskcnc 2019-07-17 10:34:37 +08:00 1
这个好, 虽然 if err!=nil 是有点啰嗦,但是对于程序稳定性真的非常好
|
6
flowfire 2019-07-17 10:37:57 +08:00
|
7
janxin 2019-07-17 10:41:47 +08:00
否决不是坏事,起码社区力量的展示吧。
|
8
Hellert 2019-07-17 10:42:30 +08:00
要解决就一次性永久解决,别搞什么中间方案,支持否决。
|
9
ruyuejun 2019-07-17 10:45:04 +08:00 2
非常 nice。
没有对写法造成根本性的改变的语法糖,我认为是不必要的。 相应的,js 的 async await 语法糖带来的是颠覆式的书写风格,利远大于弊,当然觉得很好,而 go 中的 try 不但没有根治异常处理,还带来了恶心的函数嵌套。 我理解的是 Go 社区不应该过分坚持简单、单一哲学,坚持没错,但是这个地方如此沉重,和泛型一样,应该有大刀阔斧的改革勇气 |
10
boboliu 2019-07-17 10:46:28 +08:00
这个 try 函数作为语法糖的意义确实很低…… go 目前的关键字和内置函数很克制,个人认为加这样一个隐藏细节且对程序稳定性没有好处的谜之语法糖并没有使 go 的 error handle 更友好的效果。
|
11
rrfeng 2019-07-17 10:51:28 +08:00 1
@flowfire
async await 收益巨大,傻子也能写异步了。promise 真的太难了。 try 相比之下收益太小了,错误处理还是要写,只能包一个 func (这点真的很蠢……),而且现在很多 MustFunc 写法。总之看起来就不是个好的解决方案,况且它没解决根本问题。 |
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 的?可以,不过大佬们觉得麻烦不是,我觉得这个事情社区可以再推一推 |
14
x7395759 2019-07-17 11:09:21 +08:00
支持!
|
16
qq976739120 2019-07-17 11:14:34 +08:00
try 这样的语法糖,第三方实现的很多了,喜欢的早用上了,算啥改进啊
|
17
luoyou1014 2019-07-17 11:14:54 +08:00
@janxin rust 的也很麻烦的,match match match unwrap unwrap 顺带 Some 里面的内容可能是引用的,处理起来就是一个字,烦。
|
18
ChristopherWu 2019-07-17 11:26:29 +08:00
@qq976739120 go 没有宏,怎么做语法糖?包个函数做法太奇怪了。
|
19
ChristopherWu 2019-07-17 11:27:00 +08:00
@dbskcnc 跟异常比起来,哪里对稳定性好?
|
20
petelin 2019-07-17 11:28:50 +08:00 via iPhone
有什么好 try 的
错误都不处理 还想写出来好软件 |
21
mcfog 2019-07-17 11:34:47 +08:00
@rrfeng 能用 promise 把异步写清楚的人也许十个里面只有两三个,能用 async-await 写清楚的可能就只有半个,来源于我面试下来的主观感受
|
22
qq976739120 2019-07-17 11:43:15 +08:00
@ChristopherWu https://github.com/manucorporat/try . 类似这样的,我随手搜了个,应该有更完善的
|
23
ChristopherWu 2019-07-17 11:49:01 +08:00
@qq976739120 所以都要传 lambda 过去,很奇怪的。
|
24
fatedier 2019-07-17 11:52:15 +08:00
感觉 "if err != nil " 问题不大, 并不是迫切的需求,泛型才是。
|
25
hst001 2019-07-17 11:52:36 +08:00
try 还是没解决 if err != nil 啰嗦的问题
|
26
fengjianxinghun 2019-07-17 11:56:40 +08:00 1
@dbskcnc 好个毛线,标准库内部都偷偷 panic/recover 来当异常用。假如 err 这么好,为什么还用这种自己不推荐,内部偷偷用的玩意?
|
27
blless 2019-07-17 12:09:14 +08:00 via Android
err 唯一不好用就是没有输出堆栈,return 什么的根本不是问题,代码扫描检查 error 有没有处理就很简单,只要正常处理基本不会崩溃
|
28
BBCCBB 2019-07-17 12:17:27 +08:00
这个 try 是真丑
|
29
cubecube 2019-07-17 12:21:35 +08:00 via Android
按理说 go 的程序和库都是基于源码的,不用考虑二进制兼容性,优化语言不算太麻烦的,还是那帮人太偏执。
|
30
polebug 2019-07-17 13:03:47 +08:00
支持!
不喜欢 try 写 if 更自由 |
31
wweir 2019-07-17 13:08:35 +08:00 via Android
喜欢 rust 的 err handling 方式
|
33
wweir 2019-07-17 13:50:33 +08:00 4
@xfriday rust 有 '?' 这个 bug 级语法糖。
go 代码里面,最多的 err 处理方式,也就是直接抛给上级,而这个刚好 '?' 可以解决。 有了这个,多了不敢说,60% 的 if err != nil 还是可以消除的。 并且可以很爽的玩起链式调用了,目前随便来个 err 处理,就会打断链式调用 |
34
loading 2019-07-17 13:51:51 +08:00 via Android
个人觉得 go 没必要用语法糖。
|
35
allgy 2019-07-17 14:24:28 +08:00
if err != nil 够用
|
36
dbskcnc 2019-07-17 15:01:20 +08:00
@ChristopherWu 返回值通常都得考虑,这样思维强制必须处理错误,不容易出现那种出错了还往下走的情形
|
37
dbskcnc 2019-07-17 15:03:16 +08:00
@fengjianxinghun 这个就是见仁见智而已, 不喜欢也正常,或许 rust 那样的适合您的口味
|
38
ChristopherWu 2019-07-17 15:08:28 +08:00
@fengjianxinghun 这个喷的好。。求标准库源码做例子,观摩观摩。
|
39
ChristopherWu 2019-07-17 15:10:55 +08:00
@dbskcnc 异常不也是一样要考虑?这不算优点。
|
40
dbskcnc 2019-07-17 15:14:23 +08:00
@ChristopherWu 出异常的地方通常都跟处理的地方离远了,思维不连续,并且异常容易混一起,也让人很容易偷懒
|
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 也是返回值吧。毕竟宝马跟单车都是靠轮子走的,而且都是圆的。 |
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 ? |
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) } }() ``` |
44
rrfeng 2019-07-17 15:37:15 +08:00
@mcfog
我觉得能写好 promise 的人一定能用 async/await,但是不会用 async/await 的肯定 promise 也不懂。 而且还有 async 属于新标准,很多人不一定知道并且用过…… |
45
karllynn 2019-07-17 15:37:24 +08:00
xerrors 可以输出栈了,所以都还好…泛型比较重要一些
|
46
liuguang 2019-07-17 15:38:58 +08:00
这个就是多返回值语言的优点,明明可以直接 return 多方便,try catch 和 defer 一样,只会让程序变得更慢。
defer 为了关闭资源还可以理解,而明明知道有 error,不直接处理,还在一堆代码里面 catch,不如直接 return 来的高效。 |
47
fengjianxinghun 2019-07-17 15:49:47 +08:00
@liuguang go 现在的多返回值实现是用栈来实现的,没办法像 c/c++用 rax 返回,速度慢了一大截。
|
48
dbskcnc 2019-07-17 15:56:09 +08:00
@fengjianxinghun err 或者 panic 都可以用,个人是喜欢 err, 但是有人喜欢用 panic,你也没办法,毕竟这里没有对错,只是风格喜好不同, 如果你调用的模块(库)用了 panic,只有 recover 应对, 自己写的几年 go 没用过 panic,但 recover 有时还是得用
|
49
mcfog 2019-07-17 16:06:53 +08:00 via Android
@rrfeng 所以说我观察下来就是能写写 promise 但一换 async await 就不行了的人挺多的。反过来 async await 写的好的,换 promise 也能写,就是幸福指数下降罢了,也就是说 async await 带来的字面上的简单让不少人误以为自己能轻松把异步代码写好了(然而并不)
我觉得 golang 关于语法糖的思路也是有这种拒绝虚假的幸福指数的倾向,不做让复杂的事情(异步/错误处理)表面上变简单,但并不降低实际复杂度的语法糖 |
50
xfriday 2019-07-17 16:07:08 +08:00
@neoblackcap 我认为就是 fp 那一套而已,本身没有区别,各种 or_else, map_err 我是没有看出什么优雅来,如果没有编译器优化,甚至效率都低下
|
51
xfriday 2019-07-17 16:15:09 +08:00
clear is better than clever,越是复杂的东西,推广和维护成本就越高,foo("".into()),我特么找个实现要到处去翻
|
52
ChristopherWu 2019-07-17 16:19:00 +08:00
@xfriday 本来编译器的目标之一就是优化- = -
|
53
bobuick 2019-07-17 16:20:39 +08:00
try catch 没什么卵用. 用 go 写 crud 的会感觉 try 必要性比较大, 用 go 写偏系统一点的东西, try 基本上没卵用了.
|
54
xfriday 2019-07-17 16:20:48 +08:00
rust 宣称的无数据竞争,仅仅是靠不可变来实现,这叫解决问题吗?根本就是回避问题,如果确实需要多线程共享变量,到头来还是要靠锁,rust 会打广告是真的
|
55
fengjianxinghun 2019-07-17 16:39:16 +08:00
@bobuick 别吹,go 标准库是偏系统没有 crud 吧?里面也一堆 panic/recover 当 try catch 用
|
56
TheBestSivir 2019-07-17 18:31:40 +08:00
@xfriday 不可变对象就是解决的数据竞争,代码如果是 immutable 风格的就是天然不存在并发问题的。至于线程间数据共享你认为还要上锁,是因为你用了 immutable 的 rust 写出了 java/c++的代码,不可变对象是通过 copy on read/write 来解决并发问题的。理论上不存在两个线程共享一个引用的问题
|
57
xfriday 2019-07-17 18:45:07 +08:00
@TheBestSivir Mutex,Arc、Rc、RefCell 是什么?什么叫“理论上不存在两个线程共享一个引用的问题“?真以为 rust 的 ownership 能解决所有问题?
|
58
secondwtq 2019-07-17 18:57:11 +08:00 via iPad
async/await 是帮你做 CPS,这个是有一定复杂性的,已经超过了语法糖的范畴了。
|
59
morethansean 2019-07-17 18:58:09 +08:00
@mcfog 你确定吗……反正我遇到的真实业务里能用 promise 写清楚一个稍微复杂点逻辑的比 aa 少多了……虽然不深入了解 promise 的人对 aa 也就停留在最简单的使用上,但至少他们能用这个写出代码……
|
60
secondwtq 2019-07-17 19:12:04 +08:00 via iPad
另外我倒是认为这个没必要关注也没必要吵,因为用 Go 的其实并不关注这些东西,关注这些东西的不用 Go。吵半天一点意义都没有
|
61
mcfog 2019-07-17 19:31:17 +08:00
@morethansean 写一些简单的并发和错误处理,面试过程中可能是本能以为 async/await 简单,会有人准备要用,然而最终很少有人能写出来,基本都要让他们回到用 promise 的路上
哦,如果你是说用 await 把所有的并发都变成串行也算是写出代码的话,那可能是 async/await 更容易让人写出代码 |
62
morethansean 2019-07-17 19:35:36 +08:00
@mcfog #61
为什么要把并发改写成串行?不明白你的逻辑。从使用成本上,promise 比 aa 高是很明显的事实。 |
63
secondwtq 2019-07-17 19:41:23 +08:00 via iPad
@neoblackcap 老哥受了什么刺激,为什么要对牛谈琴呢
@mcfog 我不知道你所谓的”用 async-await 写清楚”是什么意思,但是很明显的 Promise 和 async-await 不是替代关系,从能力上来说 async-await 还要比你 Promise 弱,只用 async-await 写逻辑当然是无法做到的 |
64
momo733 2019-07-17 19:48:27 +08:00 via iPhone
昨天刚投了反对票,宁愿用现在也不想要这个 try
|
66
neoblackcap 2019-07-17 20:20:20 +08:00
@secondwtq 我只是发了一次言,其实还好。我只是说明一下这东西的优势在哪里,为什么 Monad 是更好的异常处理而且。毕竟一次回复不仅仅是一个人看到。大家也可以看到。大家各取所需,觉得 golang 好的就继续写,觉得其他更好的就去写其他就好了。我觉得没什么必要纠结什么天下第一,毕竟电锯跟锤子不一样,CNC 机床也不能替代凿子。当然爱一样东西,自己能出力去让它变得更好,这样也不错。
|
67
lazyfighter 2019-07-17 21:14:28 +08:00
我最不能理解的是变量在左类型在右,我是真特么别扭
|
68
lazyfighter 2019-07-17 21:14:58 +08:00
还有一个接口的实现,不指定接口,需要参数类型相同,真尼玛傻吊
|
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())))) |
70
abscon 2019-07-18 10:41:14 +08:00
|
71
xfriday 2019-07-18 14:09:33 +08:00
@abscon 我想表达的不是你说的意思,而是看不惯 rust 吹,至于错误处理,err,exception,monad 没有哪个有绝对优势,但是 rust 粉的说话方式总是居高临下
|
72
xfriday 2019-07-18 14:10:21 +08:00
也不清楚你的第二句话是根据何种理论得出的
|
73
perfectlaugh 2019-07-18 15:08:07 +08:00
我只知道我用 rust 唯一不满的是还没有 stable async 和 windows mio
|
74
perfectlaugh 2019-07-18 15:10:26 +08:00
而且 rust 和 go 走的道路本身就不一样 有不同的情景可以用不同的工具 不好🐎?
|
75
reus 2019-07-23 13:31:57 +08:00
@fengjianxinghun https://github.com/golang/go/wiki/PanicAndRecover wiki 里都教你怎么用了,自己不知道,就说“偷偷”,呵呵。
|
76
reus 2019-07-23 13:34:35 +08:00
@fengjianxinghun 这里用 recover 有什么问题?如果代码有 bug,例如 slice 越界,recover 就可以保证其他连接不受影响。panic / recover 本来就是这样用的。
|