看了一个 go 语言,感觉语法略为不习惯。

2016-01-27 09:42:17 +08:00
 fire5
还是大 python 舒服。。
22946 次点击
所在节点    Python
151 条回复
BurNFans
2016-01-29 13:28:15 +08:00
@noli
师傅,理解不了你说要手工分析 err ,漏了的话,上线后不定期 crash ;
师傅,我写不出返回不定的多个 err 的代码,你教我好不好
noli
2016-01-29 13:41:32 +08:00
@BurNFans

假设你当我是白痴…… 估计你也不会跟白痴说话吧?不分析

假设你没有当我白痴,那么一个按照预期返回了结果的函数会 crash 吗?
你认为我会连这么基本的问题都没弄清楚的话…………嗯嗯,我和你之间必定出了一个自大狂。

为什么是可能导致?这就是我想批评 golang 的问题所在了。

回到那个讨论场景, do_transaction 会调用不定多个其他函数(例如在循环体中调用),这些函数都是可以返回 err 的。

现在其中执行到某一步的时候,某个函数返回 err 了, 那 do_transaction 中要怎么判断是否终止事务?获得这个 err 之后要怎么执行回滚?

仔细想象这个问题,你就会发现,当你调用的代码并不是直接通过源码明文调用(就是说代码中直接通过函数名调用),而是间接地调用的时候, err 的信息就是模糊的,被隐藏在调用接口之下的。那这个时候 err 信息实际上是没用的。

--

问题是如何进一步扩散变得严重的呢? 现在我的某个间接调用返回了一个 err , 那么一般来说是不是意味着这个函数没有返回程序上下文期望可以继续执行下去的返回结果?

就是说 ret, err = do_sth() 总是 要么 err 为 nil 要么 ret 为 nil ,这也是 golang 为什么能歪打正着使用这种设计的前提 convention 。

但是因为 我在 do_transaction 中并不真的 清楚 调用的函数是 do_sth1 还是 do_sth2 ,那么我的 这个 err 是不是只能靠手工穷举所有的可能性?但是又因为 do_transaction 中你所间接调用到的子过程实际上是动态的,所以所有你现在源代码中的静态穷举显然是徒劳的。

那么,总是会有没被检查到的 err 或者 ret 会扩散到后续的代码去,你总不能在所有的地方都准备好 panic 和 recover 吧?

那你现在明白为什么会不定期 crash 了没?
codeaqua
2016-01-29 13:44:03 +08:00
错误返回 和 异常机制 就别争了,没有结果的,讨厌 错误返回? 你没写过 C 么?
zhangchioulin
2016-01-29 13:45:29 +08:00
@TangMonk 谢了哥们
noli
2016-01-29 13:48:27 +08:00
@BurNFans

按照 golang 的设计方式,要调用不定多个可能产生 err 的函数的例子,这不是很常见嘛。

见你这么谦虚承认自己见识少,那我就给你举个例子吧,典型的 map_reduce 类型工作。

假设你要写一个爬虫,现在有一个要爬的 url 任务列表,你要根据这个列表去获取对应的内容并且进行分析,并且分析的时候也是调用别处的代码来分析的,分析结果也跟网络一样是有可能出错的。

那么,不管你串行也好并行也好,你总是得循环地执行这个

result, err = crawl_and_analyze(url)

现在由于这个任务列表是外部读入的,动态的

你来告诉我,你打算怎么在循环体里根据 err 找出哪里处问题了?
BurNFans
2016-01-29 13:49:20 +08:00
@noli
连错误返回和异常机制都没分清楚,确实没有跟你继续讨论的必要了。另外,你居然会觉得要在所有的地方准备 panic 和 recover ,所以不在一个频道上,没办法聊。
noli
2016-01-29 13:51:25 +08:00
@codeaqua

“没有结果”只是你的信念。
实际上,软件工程的经验就是 exception 的代码结构比 返回 err 可重用性和健壮性高得多。
noli
2016-01-29 13:52:52 +08:00
@BurNFans

你觉得你很清楚,那你倒是说嘛。
不过看你的发言风格,打一耙就走,你倒是有真小人之风。
BurNFans
2016-01-29 13:55:11 +08:00
@noli
1. 我没有做任何人身攻击
2. 我没必要跟你讨论和解释,不在一个频道上
3. 我已经浪费了时间跟你纠缠这事了
再见
noli
2016-01-29 14:57:21 +08:00
@BurNFans

你也确实没有人身攻击,我只是认为你说的东西 not helpful 。
祝你在以后的道路上少浪费生命。
cloudache
2016-01-29 15:29:49 +08:00
go 语法还是蛮好用的
bombless
2016-01-29 19:44:08 +08:00
其实无论怎样你都要包装错误的类型的,这个是没法避免的。
比如说像 C++异常这样的机制,你会 catch 一种预期的错误,然后向外抛一个你这个层面的错误,也就是中间有个转换错误类型的过程。
这种思路你换到 C 或者 Go 都是类似的,所以就这点怪罪 Go 的错误处理方式没有什么道理。

实践中倒是 C++代码用异常并不很流行,比如 Google 就在它的风格中禁止使用异常。
noli
2016-01-29 23:45:31 +08:00
@bombless C++ 不推荐用异常主要是因为没有 GC 。

返回错误,和抛出异常,根本就是不一样的结构;既不是顺序也不是分支,而是跳转,而返回错误依然是一个顺序结构之中。

异常确保不会继续向下执行,无需异常所在的上下文来保证。返回错误得自己完成这件事情。

结构的差异大概有点像 python 的 yield 和 return 。
codeaqua
2016-01-31 20:59:39 +08:00
@noli 你的意思是 C 没有异常机制, 现在的操作系统还没有你写的健壮? 还是说操作系统不是你口中的软工程?(另外,我是支持异常机制的,因为我的大多数代码很多都是统一处理错误的,但是不代表我认为 错误返回 和 异常机制 孰优孰劣,场景不一样而已,所以我说的争论没有结果,还请阁下别摆出 sibi 的态度)
noli
2016-02-02 10:13:30 +08:00
@codeaqua 如果你觉得你写任何代码都有操作系统的代码质量,加上足量的测试,那当然用什么语言健壮性都会很好。所以,我的说法是在软件工程经验来说,使用异常机制健壮性*更*容*易* 提高,可重用性更好。

我不觉得你举操作系统的例子能说明错误返具有不可替代性甚至优越性,事实上,很多操作系统也是内部实现了异常抛出机制的,只是在开源的里面很少这样做而已。

你认为错误返回和异常机制的优劣只是场景问题。那我们来说说吧,在 go 语言常用的场景,你认为什么情况下,用错误返回优与用异常 ?
codeaqua
2016-02-02 16:24:07 +08:00
@noli

void foo() throws Exception {
SomeResource r = openSomeResource();
r.do1(); // exception
r.do2();
}
这个例子正是异常机制使用不当的后果,如果项目够复杂,很多时候这种错误会难以发现。
而 error code 不会改变正常的代码 flow, 代码的走向清晰明确。
还有 错误 和 异常 是有区别的,但同时它们的界限有时又比较模糊,在不同的业务里面,有些错误是异常,有些可能是正常的结果(仅仅是他的类型里面有 Error 这个字样而已,但它应该被视为一个普普通通的类型)。
exception 有好处有坏处,而好处和坏处都是来自于同一个特性----改变正常的代码 flow

另外程序界到现在还没有得出的结论你是怎么得出来 xxx 比 xxx 更好的?
我不想再跟你争了,因为我一开始就说了没结果的!
codeaqua
2016-02-02 16:28:02 +08:00
@noli
"我不觉得你举操作系统的例子能说明错误返具有不可替代性甚至优越性",阁下别老是自己 yy ,我有表达你所说的这种观点吗?
codeaqua
2016-02-02 16:47:16 +08:00
c#我也在写,别拿 c#的 async 和 await 来和 golang 比,没有可比性, golang 真正的优势在于解决了异步模型的侵入性问题,什么是侵入性自己去 google 。
上面某楼从别人网站挖的测试图,代码实现都不一样,根本没有参考价值,我写过一个 1000W 长度的随机整形数组排序测试, rust 是 0.9s , go 是 1.1s , vc 是 1.8s ,算法完全一致,我不是要表达 go 比 c 还快, vc 的编译器问题罢了,比如用 clang ,但是这个测试可以说明 go 的速度问题
noli
2016-02-02 18:30:48 +08:00
@codeaqua 如果返回错误并不具有不可替代性和优越性,那么按照简单的逻辑,抛出异常的做法就是具有不可替代型和优越性——这是我的观点。逻辑上是这么说当然是不够的,但是我也在此前的回复中说明了,什么情况下,抛出异常是比返回错误更合理更符合实践的做法。

你举的那个例子叫做 checked exception 的语法——声明了这种异常就一定要 catch ,这个只是脑残 Java 的特例, C# C++ 的 exception 都不会要求声明阶段指定 exception ;所以才会导致程序员不得不用偷懒的办法——是的,这就是偷懒,你说的这种情况——声明抛出任意异常——依然是程序员偷懒而不是异常机制有什么问题,只要程序员想“偷懒”,返回一个 err 一样可以绕过——更重要的是,返回一个 err 更容易导致 callsite 出现疏漏的问题,情形也是我此前所说的,在一个方法调用中可能出现不定多种 err ,,处理对应 err 的缺失会导致 panic 出现在预期以外的位置,更难调查。

--

golang 无非就是有 channel 这种东西吧,这也能够叫做非引入地解决异步模型问题?那什么语言不能呢?这本来就只是一个编程语言的库就可以解决的问题而已。

别卖弄你的术语,侵入式 intrusive 写过 C++ 的人都知道是什么意思,倒是你把 intrusive  这个词用在同步异步模型,倒是创举了。

如果你是想说“异步代码的传染性”,譬如 C# 里面的 async 关键字会传染得到处都是,而 golang 没有这个问题。 那你真是太小看 C# 了。

golang 在这个问题上唯一的优势就是,语言规定死了这样解决异步问题,不需要发明其他的框架——然而在我看来,这样的语言也就适合代码流水线上的工人去用了。跟 Java 没什么两样。
codeaqua
2016-02-02 18:40:31 +08:00
@noli
"如果返回错误并不具有不可替代性和优越性,那么按照简单的逻辑,抛出异常的做法就是具有不可替代型和优越性",你的逻辑我实在是看不懂。。。。

“ golang 无非就是有 channel 这种东西吧,这也能够叫做非引入地解决异步模型问题?那什么语言不能呢?这本来就只是一个编程语言的库就可以解决的问题而已”, 侵入性。。。。哎,我无法和你沟通了,懂的人自然懂,不懂的我懒得解释了,解决了异步模型侵入性问题的目前有 3 个, go, erlang, python 的 gevent 框架, gevent 是通过替换标准库实现的。

还有,从你的对话里面看的出阁下对自己排斥的事物会一黑到底,俗称偏执狂

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/253629

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX