Go语言的赞和喷
(原发于 GitHub Pages,2019-01-01 23:22:43)
2019 年,我回来了。
不知不觉中,我入 PHP 的坑已经 3 年有余,入 Go 的坑也大半年了。作为不评论不舒服斯基星人,自然要对 Go 品头论足一番的。
总的一句话,Go 的一些特性确实恰到好处,然而更多的地方却是平庸、繁琐、束缚,以至于我想不到它是适合哪些场景的。
静态语言里,C、C++ 有着明显的适用领域:你要想老老实实写程序,不玩任何花招,就用 C 吧,至少你能掌控一切,实在想玩你还有宏这个大杀器;你要想玩点花招,那就用 C++,代价就是需要自身水平更高,能掌控到多大层次就写多大层次,不懂的不要不懂装懂去用,总体来说还是安全的。
脚本语言里,如果要随便写点什么工具,python 啥的挺方便的;写点网络的,就用世界上最好的语言 PHP 吧。什么?你说 Java?实在没办法,体量太大,公司要你用你就用吧。不过就其本质而言,其实 Java 和今天的主角——Go 是同一类的。不是说他们语法像,是指应用场景(不过这个领域拿 PHP 写显然会更爽)。
嗯——为了表达出真实的意思,我想用词稍微犀利点,请先做一下心理建设。
我不怎么懂 Java,就我浅薄的了解而言,如果你的公司、团队有很多傻逼,甚至你自己也是,业务上又正好可以用 Java 界的一些现成的框架、组件,那么用 Java 肯定是没错的啦。它确实有一种魔力,让你无论多傻逼,也绝对写不出错得多么隐蔽、精妙无比的代码;同时让你无论多牛逼,也写不出多么精彩绝伦、言简意赅的代码。Go 也有这种特质,甚至有些地方比起 Java 更有过之而不及。不信请看:
别人家的写法:
r = f(p1, p2 != null ? p2 : p3)
$r = f($p1, $p2 ?? $p3)
Go 家的写法:
var r someType
if p2 != nil {
r = f(p1, p2)
} else {
r = f(p1, p3)
}
为什么要设计成这样?Go 爸爸说:你们有些人啊,会嵌套很多层 ?:
,导致代码可读性太差啦,于是禁止你们使用 ?:
,这是家法。在这里,作为熊孩子的代表,我来告诉大家怎样写出让 Go 爸爸无语的代码:
foo := 1
bar := 2
var foobar int
if foo > bar { if bar > 1 { foobar = 1 } else if bar < 0 { foobar = 2 } else { foobar = 3 } } else { if foo >= 3 { foobar = 4 } else { foobar = 5 } }
怎么样?可读性差不差?
看到了吧,这种傻逼是防不住的,他愿意把 ?: 嵌套好多层,它同样可能会把 if else
嵌套好多层。有素质的人会怎么做?遇到 ?:
嵌套太多立马拆成 if else
。所以结论是,即使去掉 ?:
,傻逼还是傻逼,但是正常的人写代码就会很啰嗦;支持 ?:
,傻逼还是傻逼,正常人用起来爽。要知道一层 ?: 的场景占所有 ?:
场景的比例还是很高的吧。我觉得可以这样,Go 爸爸可以统计一些工业级代码库的 ?:
嵌套层数,作为数据支撑(比如自家 Chrome 里一层 ?:
占 95%,两层占 4.9),然后再在语言层面只支持一层 ?:
,编译参数可选打开两层,不支持两层以上。这就功在千秋了。
除了 不支持 ?:
,Go 爸爸还有很多这样的设计,随便举几个例子:
- 不支持默认参数
- 不支持运算符重载
- 不提供 goroutine id(以及 gls、可重入锁)
特别是第三点,也是这种思路,因为你们可能会滥用,所以我不提供。类似这种“爸爸思路”,是我今天要喷的最大喷点。前两点也许是抄 Java 的,不怪 Go 爸爸。
综上,Go 爸爸通过扼杀一些基本语法或者一些基础信息,来防止傻逼干坏事,同时让正常人用起来很啰嗦,同时还可能防止不了傻逼干坏事。这跟 Java 通过不提供高级语法来防止傻逼干坏事是师出同门啊,而且他们正好都能写网络服务程序,你说它们像不像?
然而,Go 爸爸也有精分的时候,它居然发明语法糖了耶!比如 if
可以执行一个句句。单就这个语法而言,我的态度是中立偏赞。赞是赞 Go 爸爸确实用过心了,某些时候挺方便,还能缩小变量作用域;不过这个总归是可有可无的,毕竟换一行写也不会死,要变量作用域加个大括号就行。
小语法方面倒是有个亮点,那就是 switch 的隐式 break、显式 fallthrough 处理。不多展开了。
除了防傻逼,Go 爸爸还有一个思路,就是只许州官放火,不许百姓点灯。有两个语法点——
- 泛型
- 逗号ok断言
先说泛型吧。不支持泛型其实我挺能理解的,因为他确实比 ?:
复杂多了,傻逼用不起,?:
都没有,怎么可能会有泛型呢。然而 Go 爸爸有特权呀,它的 map、chan 可都是泛型的哦。但是你要写一个泛型的语法结构的话,对不起没有。
再说逗号ok断言,同样 Go 爸爸要得起,我们要不起。其实我更想要一个这样的语法:当返回值是 xxx, ok 或者 xxx, err 的时候,我如果用一个返回值接,那么就返回第一个,以便链式调用,同时 !ok 或者 err != nil 的时候 panic。
以上两小点虽然是在喷,不过还好啦。无所谓的。下面讲几个大的方面。
代码组织
我特别赞赏 Go 对于 package 级严格的循环依赖检查。然而如果加上其他规则:
- 一个目录一个 package
- 不同路径下的同名目录也是不同 package
- go 代码无法拆成 .h、.cpp
实际可操作性就会非常差。要拆 package,就要把依赖关系梳理得特别严格,半点不得马虎。这对工一般的程代码来说是个极大的挑战。
我更倾向于做成函数级循环依赖检查,或者不限制(毕竟递归函数也是要支持的嘛)。
这部分,中立偏喷,偏喷是因为 Go 爸爸用了我的小名 internal。
OOP
我特别赞赏 Go 对于 OOP 泛滥成灾的思考与探索,以及对于终结这阵 Java 带来的不正之风的决心。怎么可能万物都是 class 呢。但同时,Go 还是有点矫枉过正的,如果我需要利用传统的 OOP 来搞事情,就非常麻烦,你甚至都无法写出一个框架来。你只能写库让别人用。虽然我也不喜欢框架,但有的时候是需要框架的。
defer 非常切中痛点,特别解决一堆错误 return 外加资源释放的问题。相比之下C 里只能用 goto,C++ 本身不支持但可以玩出 LOKI_ON_BLOCK_EXIT 或者 BOOST_SCOPE_EXIT。defer 一举解决问题。(要是能再增加命名 defer 以及撤销 defer 的功能就更好了。没错,你也许看出来了,我觉得 LOKI_ON_BLOCK_EXIT 是最完美的方案。)
虽然 defer 很好,但不意味着析构就没用武之地了。理想的情况是,析构、多态、defer 都要有……
这部分我的态度是中立。
错误处理
终于要点赞了。错误处理是在我看来 go 完胜的地方,恰到好处地处理问题,又防止滥用。也矫正 Java 带来的歪风邪气。
Java 的设计,让人不得不用异常来处理业务。甚至 Java 自己还帮我们分好类了:一种是不是异常的异常,用来处理业务;另一种是真的异常。一些用惯 Java 的傻逼跑到 C++、PHP、Python 里乱拉屎,到处是 try catch。
Go 爸爸一声令下,万籁俱寂。
goroutine
最后不得不说说 gorouthine,毕竟是卖点嘛。我的态度中立偏赞。赞是因为这是一种太有创意的方案,居然想在在语言层面解决多线程、并发问题;不过我还是觉得这更多的是应用层面的问题,做到官方库里会更好,而不是做成语法。
总结
刚开始用 Go 的时候,特别亮眼,简直处处是亮点,然后越接触越讨厌,一点也不耐看……看得出来,设计者糅合了 C、python、Java 的一些特性,并融入了自己的独特的理解。Go的设计者真的特别特立独行且坚持己见,一些我喜欢的特性因为他们的坚持而存在下来,一些我讨厌的特性也因为他们的坚(Gu)持(Zhi)而不能有所改观。就这样的 Go,想代替 C 作为系统语言,是没戏的;想在网络服务有一番作为,抢 Java 的份额,或许是有机会的,不过最多只能抢 Java 的,连 C# 的都抢不了,C++、PHP 更抢不了。
嗯,除了特定的不得不用的场合,反正我是不会特意用 Go 的。
2019,新年快乐!
Go语言的赞和喷的更多相关文章
- NLP系列(4)_朴素贝叶斯实战与进阶
作者: 寒小阳 && 龙心尘 时间:2016年2月. 出处:http://blog.csdn.net/han_xiaoyang/article/details/50629608 htt ...
- NLP系列(4)_朴素贝叶斯实战与进阶(转)
http://blog.csdn.net/han_xiaoyang/article/details/50629608 作者: 寒小阳 && 龙心尘 时间:2016年2月. 出处:htt ...
- Kotlin 的优缺点
从Android 7.0开始,谷歌使用的API从Oracle JDK切换到了open JDK,这对于谷歌来说是一个艰难的决定.对于开发者来说,却倍感兴奋,这意味着长期的官司问题也许就此结束,Andro ...
- 超赞的 Go 语言 INI 文件操作
灵活的数据源 不光光可以从文件读取配置,还支持 []byte 类型的纯数据读取和基于 io.ReadCloser 的流式读取. 多种格式兼容 各种文件种类的广泛支持,包括但不限于 my.cnf..gi ...
- 学习使用C语言/C++编程的7个步骤!超赞~
C是一种编译性语言.如果你以前从来没有接触过任何的编程语言,那么你则需要学习一下一个拆分的逻辑思维.当我们想要写一个项目或者软件的时候,我们需要把这个整体拆分为7个步骤,这样也会让你的思路看起来更有条 ...
- 3行python代码翻译70种语言,这个OCR神奇太赞了
写在前面的一些P话: 今天给大家介绍一个超级简单且强大的OCR文本识别工具:easyocr. 这个模块支持70多种语言的即用型OCR,包括中文,日文,韩文和泰文等.完全满足了大家对于语言的要求,不管你 ...
- 转 - Web新人(偏前端)应该怎样学习(个人观点,勿喷)
我自己是会计专业,转行自学web的,学习有一两年了,也还是新人一个,只不过不是那种超级“新”的,所以有什么话说得不对,请轻喷.欢迎大家来和我交流. 1.我能不能转行学web? 能不能学web这个不是别 ...
- 跨越语言的障碍:C++/CLI 调用 C#
首先我想投诉一下博客园首页右边栏的广告..最近总是出现很恐怖的整容脸的广告.真的是吓坏了.=.=大家有同感吗? 博客园前一阵子掀起了语言的广泛讨论,事实上语言的争执在整个程序员圈子也没有停止过.以我个 ...
- 嵌入式开发中常见3个的C语言技巧
Hey,大家好!我是CrazyCatJack.今天我来说几个在嵌入式开发中常用的C语言技巧吧.也许你曾经用过,也许你只是见到过但是没有深入理解.那么今天好好补充下吧^_^ 1.指向函数的指针 指针不光 ...
- c语言第一章第一节 认识变量
声明:本人大一新生,闲着无聊..写写c语言教程..菜鸟一枚..大神勿喷!!! 接下来我们都用dev来进行编译..vc++太古老了,没提示功能,不好上手,并且老是出毛病..vs太大了,编个c不至于,运行 ...
随机推荐
- do-while循环的使用
一.循环结构的4个要素 ① 初始化条件 ② 循环条件 --->是boolean类型 ③ 循环体 ④ 迭代条件 二.do-while循环结构: ①do{ ③; ④;}while(②); 执行过程: ...
- 4.MongoDB系列之索引(一)
1. 执行计划查看 db.getCollection('users').find({'username': 'shenjian'}).explain('executionStats') 结果查看,先大 ...
- 【题解】CF1720C
题意简述 给你一个 01 矩阵,每一次你可以在这个矩阵中找到一个 \(L\) 型,将它全部变成 0.\(L\) 型的定义是在一个 \(2\times2\) 矩阵中,除开一个角之外的图形,其中必须包含至 ...
- 创建Vue工程常用的命令
创建一个vue项目的步骤 1.创建一个名称为myapp的工程 vue init webpack myapp 2.进入工程目录 cd myapp 3.安装 vue-router npm install ...
- C#--对上传的Excel文档的处理
注:ToString对数值字符串的处理 string nID=555; nID.ToString("00000000"); ---00000555 var oFile = Re ...
- Python--网络编程学习笔记系列02 附:tcp服务端,tcp客户端
Python--网络编程学习笔记系列02 TCP和UDP的概述: udp通信模型类似于写信,不需要建立相关链接,只需要发送数据即可(现在几乎不用:不稳定,不安全) tcp通信模型类似于打电话,一定要建 ...
- MyBatis&Spring Framrwork
1. MyBatis 1.1 概述 MyBatis是一款优秀的持久层框架,用于简化JDBC开发 MyBatis本是Apache的一个开源项目iBatis,2010年这个项目迁移到了google cod ...
- 通过Jenkins,执行远程服务器的自动化脚本
通过Jenkins,可自动执行写好的应用部署.自动化测试等的脚本工具,实现测试环境的应用自动定时更新.自动执行测试等. 1. 安装SSH插件 进入[系统管理]-[插件管理]-[可用插件],搜索Publ ...
- C#多线程之高级篇(上)
前言 抛开死锁不谈,只聊性能问题,尽管锁总能粗暴的满足同步需求,但一旦存在竞争关系,意味着一定会有线程被阻塞,竞争越激烈,被阻塞的线程越多,上下文切换次数越多,调度成本越大,显然在高并发的场景下会损害 ...
- Easy-Classification-验证码识别
1.背景 Easy-Classification是一个应用于分类任务的深度学习框架,它集成了众多成熟的分类神经网络模型,可帮助使用者简单快速的构建分类训练任务. 案例源代码 Easy-Classi ...