全文共字,预计学习时长12分钟
图源:morioh编程语言是程序员的主要工具,我们和这些抽象工具之间存在着某种密切的联系。
没错,本文又是一篇介绍广泛流行、新派而总体上很独特的编程语言——Go的文章。然而,为了像Go一样“简单、特别、有用”,我不会重述别人已经写过的东西。
我将尝试通过分析Golang的设计方案、背景与其鲜明的特点,以及今天它能如何有效运用来形成一个新的愿景。
Gopher外观先来看看下面这些论点:
·Go是不同的,但又很像。
·Go是独特的,但又没有特色。
·Go是年轻的,但却已经普及
·Go很小的,却又是强大的。
·Go简单,却又相当复杂。
·Go是独立运行的,却又是众多实例。
·Go是一种语言,但也是一种理念。
现在我们就来深入探讨一下这些观点。
创建背景
要想充分理解Golang的本质,需要深入了解其创建背景。由于当时的工具无法解决Google所面临的问题,Go就在强烈的变革需求中诞生了。
Golang的创建者RobPike说:“Go项目致力于解决Google软件开发缓慢和笨拙的问题,从而使该过程更高效和更具可扩展性。该语言是由编写、阅读、调试和维护大型软件系统的人所设计,这也是为他们自己所设计的。”
这就是说,设计Go时,有一系列特殊的问题要解决,最初拥有C、Pascal、Modula和Oberon等高级编程语言的最佳特性的坚实基础。它还牢记了Python、C++、Java等语言的有用特性,这些就是Go要解决的问题。
语言差异
然而,这绝不是要复制成功品,而是要想出新的解决方法来处理问题。有时候为了解决一个问题,需要放弃已经被证明无效的东西。而因此,Go的每一个特性大多源于主要约束,比如:
·有刻意简化和清晰的语法,以达到可读、易学、易上手的目的。
·有严格、安全、完全静态化的数据型语义,以便在编译时处理静态错误,加快执行和构建速度。
·有一个垃圾收集器,虽然该垃圾收集器能有效处理内存不安全问题,保持合理的高执行速度和成熟的资源效率。
·缺少共性和语法糖,以达到最小化、精确化、简单化的目的,因为仅有唯一解决特定问题的方法,只有一种使用风格,可明显加快开发、调试、审查和测试过程,使维护工作变得更加容易。
·缺乏面向对象(OOP)的共同原则,如继承、类和普通接口,以解决OOP的批评,自从功能导向的语言兴起后,OOP的批评越来越多,虽然作为多范式语言的Go也是其中之一。另外,这也有助于实现正构性。
·有vendoring(从1.11开始被GoModules所取代),这是一个强大的依赖管理系统,它的汇编器非常接近二进制代码,可实现快速构建,然后实现非常轻量级和二进制文件的大小效率。这使得它能与微服务架构模式以及一般的云原生开发完美匹配。
·没有try-catch异常处理。尽管饱受争议和诟病,但这其实是Golang处理错误的惯用方式,这实际上有很多好处:避免重复的错误处理代码,保持控制流的高效和执行速度,保持代码的干净和可读性,简化代码编写和调试。
可以看到,Go的开发者已经成功想出一套非常高效的语言约束系统,可实现其一些最大特点和功能。这种做法令人印象深刻,通过使用每一个约束条件,它成功地同时实现了多个主要特点。
应指出,我在这里定义的将Go的特性建立在其约束条件上的方法,并不完全是基于其创建者的名言、博客文章或演讲、语言的官方文件或其他作者的文章,其实这是我的个人理解和描述Golang的本质以及其独特性的方式。当然,你可以不同意我的观点,也希望你不要完全相信我说的话,要自己去研究。
而且在这一点上,Go与其他语言有很明显的不同,因为它们是通过添加新特性而共同进化的,从而增加了复杂性并变得越来越趋同,而Go则是先用一种方法来约束自己,然后大部分从一开始就保持了有限性。
“很多Go的新人都会要求从所知的语言中获取功能。但这些特性并不属于Go——而且语言是固定的。给Go添加功能不会让它变得更好,只是让它变得更大。这将使Go因少了点不同而变得不那么有趣。”
鲜明的特点
然而,这并不一定意味着Go存在缺陷或缺少重要的功能特性。事实上,这将使编程变得毫无用处,因为完全可以先用汇编语言,但Go并非如此。为了保持简单,Go非常刻意地避免在不解决问题的情况下增加复杂性的功能。
不必要的特性增加复杂性,却失去了清晰性。图源:ReneeFrench
那么那些已经属于Go的功能呢?其实刻意简化的规则对他们来说也是很有作用的。Golang的创建者们做了一件令人难以置信的工作,他们创造了一个看似简单易用的东西,而它实际上是非常复杂的。
“Go其实很复杂。它是我所做过的最复杂的东西之一,但是它却让人觉得很简单......它需要大量的设计、思考、实现工作、完善。简单是隐藏复杂的艺术!”
让我们来看看Go中几个“简单”的东西:
·垃圾回收器实际上是Go最简单的功能,因为它没有任何控制接口。但其实它也是最复杂的功能,因为它在提供完整的内存安全的同时,还能节省极高的运行速度,并提供惊人的资源效率。
无论如何,Go并不是最快的编程语言,Rust、Julia、C++和C会更快。但这些语言都没有GC,因此它们没有Go那么简单,其实也没有比Go快多少。不过在大多数情况下,这也是为了给下一个特别简单的功能做让步。
ConcurrentgophersConcurrency又名Goroutines,一般来说,Concurrency模型是迄今为止最简单、最直接的实现方式。事实上,生成新的子进程的过程非常简单,只要输入go就可以了。
·接口显然是Golang最鲜明、最具辨识度的特点之一。他们独特的设计方案独自解决了大部分OOP的诟病,实现了正交性和真正的组件架构,虽然只是一套毫无价值的方法,但仍然隐藏着一些巧妙的设计技巧。
·Packages可以不间断地工作,没有任何意外,而且使用感也很好,特别是导入东西的时候。使用goget工具,可以从任何地方进行:Gopkg,GitHub,GitLab,BitBucket,甚至是你自己的托管仓库源。但为了实现组件化、模块化、可扩展性、共享、数据隐藏和隔离等等,我猜它们背后也相当复杂。
·Go的Standardlibrary中有一大堆非常方便的功能,这证明了Golang其实是一个功能相当丰富的语言。然而,这些功能的实现方式是它的独特之处。例如,使用import“net/