为什么不用用Go?
本文翻译自 Dr. Dobb's主编Andrew Binstock的文章"Why Not Go?"。
Go是一种对系统原生语言的重要反思,它对C语言做了重大的改善,同时还保持了语言的极简性。
今年早些时候,我们写了一篇有关新兴系统原生(native)语言的文章。这些语言包括D、Go、Rust以及Vala。当时我们承诺将会对这些语言进行 细致的探索。从本周开始,我们将开启一系列对来自Google的新语言Go的探索之旅,该系列共有五部分。不同于以往Dr.Dobb's的教程系列,我们 会在连续的几周内发表这些文章,这样你就可以及时且更快的了解到这门语言了。
与这个列表上的其他语言相比,Go语言对我更加有吸引力。虽然我不是Go语言专家,但我喜欢到目前为止我看到的有关Go的一切。正如你所见到的,我的愉悦 来自于对完备的语言特性选择的欣赏,而不是新语言首次亮相所带来的那种热情(我承认我也很容易受到这种兴奋带来的影响 – 这就是为什么我能识别出与喜欢Go的原因的不同之处)。下面这些特性对我尤其有吸引力:
简单而快捷的编译。Go语言编译速度很快。事实上,它的编译速度如此之快,可以轻松地被当作脚本语言使用。编译速度这么快的几个原因包括它 没有使用头文件;如果一个模块依赖A,而A依赖B,那么当A中发生一个改变时,只需要重新编译A原模块以及A的依赖即可;最后一点,目标模块包含了足够的 依赖信息,这样编译器不再需要make文件。你只需简单地进行主模块的编译,它就会自动编译工程中的所有需要被更新的模块。这是不是很酷呢?
通过多个返回值的错误处理。现今在系统原生语言中有两类主要的错误处理范式:类似C中的返回值,或类似OO语言中的异常。这两种范式都不那 么理想。但在这两者之中,返回值范式更加让人沮丧,因为返回的错误码经常与从函数中返回的其他数据相冲突。Go通过允许函数返回多个值的方式解决了这个问 题。你可以指定一个从函数返回的值代表类型错误,并可以在任意函数返回的时刻对其进行检查。如果你不关心这个错误值,你可以不检查它。无论哪种情况,函数 的常规返回值都可供你使用。
简化的组合(而不是继承)。就像在Java中那样,通过使用interface指定行为,类型可以作为对象的成员。例如,标准库中的io包 定义了一个Writer,该接口指定了一个方法:一个Write函数,以字符数组作为输入参数,返回整型值和错误类型。任何实现了与这个Write方法签 名相同的类型都是io.Writer接口的一个事实上的实现。这个设计优雅地解除了代码中的耦合。它同时也简化了单元测试时mock对象的实现。例如,如 果你想要测试一个Database对象中的方法,在标准语言中你需要创建一个Database对象来创建mock,这个对象需要大量初始化和协议实现工 作。在Go语言中,如果这个被测试的方法实现了某个interface,那么你可以使用这个接口创建任意对象,用起来很方便。这样你就可以创建 MockDatabase,它是一个最小对象,仅需实现一些必要的方法以使用这个需要被mock的interface – 无需构造函数,无需新增特性,只要方法。
简化的并发。在Go中并发相当的容易。将关键字'go'放在任意函数前面,这个函数就会在其自己的go-routine(一个非常轻量的线 程)里面运行。Go-routine之间通过channel通信,channel在本质上是一种阻塞消息队列。常见的互斥工具在Go中都具备,但Go语言 通过启动并发任务以及通过channel协作的方式简化了这类操作。
非常棒的错误消息。在我见过的语言中没有哪门语言在输出诊断信息方面能与Go想媲美。例如,如果一个程序死锁了,Go运行时会通知你,甚至可以达到告诉你哪个线程导致这次死锁的程度。编译器输出的错误信息也十分详细和有用。
大杂烩:Go语言还有其他极具吸引力的特性,这里带大家快速浏览一遍:高阶函数,垃圾收集,hashmap以及内置到语言(语言语法的一部分,不是通过库引入的)中的可扩展的数组。
当然,不是所有东西都是彩虹棒棒糖。这个工具仍然不成熟,开发社区规模也很小,但有Google这样的公司作为Go语言的后盾,这两方面不足肯定会被弥补 的。许多语言 – 尤其是D、Dust以及Vala,致力于简化C++以及增加特定特性,这让我感觉它们更像是"带有更好特性的C++",而Go语言,其设计内涵中有一种对 系统原生语言要如何运转的重要的反思。正是出于这种认识,一个去除了许多问题的优雅实现诞生了。即使你没有什么特别的需求考虑去使用Go语言,那么我认为 用你最直接的方式去了解这门语言,你会发现Go的许多特性会让你赏心悦目。Cheers!
评论