(原发于 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 爸爸还有很多这样的设计,随便举几个例子:

  1. 不支持默认参数
  2. 不支持运算符重载
  3. 不提供 goroutine id(以及 gls、可重入锁)

特别是第三点,也是这种思路,因为你们可能会滥用,所以我不提供。类似这种“爸爸思路”,是我今天要喷的最大喷点。前两点也许是抄 Java 的,不怪 Go 爸爸。

综上,Go 爸爸通过扼杀一些基本语法或者一些基础信息,来防止傻逼干坏事,同时让正常人用起来很啰嗦,同时还可能防止不了傻逼干坏事。这跟 Java 通过不提供高级语法来防止傻逼干坏事是师出同门啊,而且他们正好都能写网络服务程序,你说它们像不像?

然而,Go 爸爸也有精分的时候,它居然发明语法糖了耶!比如 if 可以执行一个句句。单就这个语法而言,我的态度是中立偏赞。赞是赞 Go 爸爸确实用过心了,某些时候挺方便,还能缩小变量作用域;不过这个总归是可有可无的,毕竟换一行写也不会死,要变量作用域加个大括号就行。

小语法方面倒是有个亮点,那就是 switch 的隐式 break、显式 fallthrough 处理。不多展开了。

除了防傻逼,Go 爸爸还有一个思路,就是只许州官放火,不许百姓点灯。有两个语法点——

  1. 泛型
  2. 逗号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语言的赞和喷的更多相关文章

  1. NLP系列(4)_朴素贝叶斯实战与进阶

    作者: 寒小阳 && 龙心尘 时间:2016年2月. 出处:http://blog.csdn.net/han_xiaoyang/article/details/50629608 htt ...

  2. NLP系列(4)_朴素贝叶斯实战与进阶(转)

    http://blog.csdn.net/han_xiaoyang/article/details/50629608 作者: 寒小阳 && 龙心尘 时间:2016年2月. 出处:htt ...

  3. Kotlin 的优缺点

    从Android 7.0开始,谷歌使用的API从Oracle JDK切换到了open JDK,这对于谷歌来说是一个艰难的决定.对于开发者来说,却倍感兴奋,这意味着长期的官司问题也许就此结束,Andro ...

  4. 超赞的 Go 语言 INI 文件操作

    灵活的数据源 不光光可以从文件读取配置,还支持 []byte 类型的纯数据读取和基于 io.ReadCloser 的流式读取. 多种格式兼容 各种文件种类的广泛支持,包括但不限于 my.cnf..gi ...

  5. 学习使用C语言/C++编程的7个步骤!超赞~

    C是一种编译性语言.如果你以前从来没有接触过任何的编程语言,那么你则需要学习一下一个拆分的逻辑思维.当我们想要写一个项目或者软件的时候,我们需要把这个整体拆分为7个步骤,这样也会让你的思路看起来更有条 ...

  6. 3行python代码翻译70种语言,这个OCR神奇太赞了

    写在前面的一些P话: 今天给大家介绍一个超级简单且强大的OCR文本识别工具:easyocr. 这个模块支持70多种语言的即用型OCR,包括中文,日文,韩文和泰文等.完全满足了大家对于语言的要求,不管你 ...

  7. 转 - Web新人(偏前端)应该怎样学习(个人观点,勿喷)

    我自己是会计专业,转行自学web的,学习有一两年了,也还是新人一个,只不过不是那种超级“新”的,所以有什么话说得不对,请轻喷.欢迎大家来和我交流. 1.我能不能转行学web? 能不能学web这个不是别 ...

  8. 跨越语言的障碍:C++/CLI 调用 C#

    首先我想投诉一下博客园首页右边栏的广告..最近总是出现很恐怖的整容脸的广告.真的是吓坏了.=.=大家有同感吗? 博客园前一阵子掀起了语言的广泛讨论,事实上语言的争执在整个程序员圈子也没有停止过.以我个 ...

  9. 嵌入式开发中常见3个的C语言技巧

    Hey,大家好!我是CrazyCatJack.今天我来说几个在嵌入式开发中常用的C语言技巧吧.也许你曾经用过,也许你只是见到过但是没有深入理解.那么今天好好补充下吧^_^ 1.指向函数的指针 指针不光 ...

  10. c语言第一章第一节 认识变量

    声明:本人大一新生,闲着无聊..写写c语言教程..菜鸟一枚..大神勿喷!!! 接下来我们都用dev来进行编译..vc++太古老了,没提示功能,不好上手,并且老是出毛病..vs太大了,编个c不至于,运行 ...

随机推荐

  1. java.lang.ClassNotFoundException: Cannot find class: “com.mysql.jdbc.Driver“的报错问题

    @Testpublic void testConnectionTest5() throws Exception { //1.读取配置文件,获取4个基本信息 InputStream is = Conne ...

  2. 8.RabbitMQ系列之RPC

    1. RPC Remote Procedure Call:远程过程调用,一次远程过程调用的流程即客户端发送一个请求到服务端,服务端根据请求信息进行处理后返回响应信息,客户端收到响应信息后结束 2. C ...

  3. 6.RabbitMQ系列之direct直连交换器

    我们通过fanout exchange(扇型交换机)实现生产者发送一个消息,这个消息同时被传送给所有队列.但是有时我们不希望所有的消息都被所有队列接收,我们希望可以指定类型为a的消息只能被队列A接收, ...

  4. 2.pytest前后置(固件、夹具)处理

    一.setup/teardown/setup_calss/teardown_class 为什么需要这些功能? 比如:我们执行用例之前,需要做的哪些操作,我们用例执行之后,需要做哪些操作 # 在所有用例 ...

  5. rocky8删除/etc/fstab 和/boot/所有文件,通过光盘救援模式恢复

    rocky8删除/etc/fstab 和/boot/所有文件,通过光盘救援模式恢复 mkdir /rootdir 先通过df和lsblk确定那个分区是根,如果确定不了,就先挂载一个分区,查看里边的文件 ...

  6. javascript异步编程,promise概念

    javascript 异步编程 概述 采用单线程模式工作的原因: 避免多线dom操作同步问题,javascript的执行环境中负责执行代码的线程只有一个 内容概要 同步模式和异步模式 事件循环和消息队 ...

  7. Golang-Gin Response 统一返回restful格式的数据

    目的: gin返回restful格式的数据,返回的200,201 的数据 也包括异常时的404/500等情况 直接调用即可 package response import ( "github ...

  8. 你不知道的React Developer Tools,20 分钟带你掌握 9 个 React 组件调试技巧

    壹 ❀ 引 React Developer Tools 是 React 官方推出的开发者插件,可以毫不夸张的说,它在我们日常组件开发中,对于组件属性以及文件定位,props 排查等等场景都扮演者至关重 ...

  9. 【题解】CF991C Candies

    题面传送门 解决思路 看到 \(10^{18}\) 的范围,我们可以想到二分答案.只要对于每一个二分出的答案进行 \(check\) ,如果可行就往比它小的半边找,不可行就往比它大的半边找. 以下是 ...

  10. toB应用私有化交付发展历程、技术对比和选型

    由于数据隐私和网络安全的考虑,大多数toB场景的客户需要私有化应用交付,也就是需要交付到客户的环境里,这样的客户有政府.金融.军工.公安.大型企业.特色行业等,这些私有化场景限制很多,如何提高私有化应 ...