所谓编程语言的设计哲学,就是指决定这门语言演化进程的高级原则和依据。
设计哲学之于编程语言,就好比一个人的价值观之于这个人的行为。因此,在真正开始学习 Go 语法和编码之前,我们还需要先来了解一下 Go 语言的设计哲学。
Go 语言的设计哲学总结为五点:简单、显式、组合、并发和面向工程。
简单:
- Go 语法层面上呈现了这样的状态:
- 仅有 25 个关键字,主流编程语言最少;
- 内置垃圾收集,降低开发人员内存管理的心智负担;
- 首字母大小写决定可见性,无需通过额外关键字修饰;
- 变量初始为类型零值,避免以随机值作为初值的问题;
- 内置数组边界检查,极大减少越界访问带来的安全隐患;
- 内置并发支持,简化并发程序设计;
- 内置接口类型,为组合的设计哲学奠定基础;
- 原生提供完善的工具链,开箱即用;
- … …
显式:
在 Go 语言中,不同类型变量是不能在一起进行混合计算的,这是因为 Go 希望开发人员明确知道自己在做什么,这与 C 语言的“信任程序员”原则完全不同,因此你需要以显式的方式通过转型统一参与计算各个变量的类型。
除此之外,Go 设计者所崇尚的显式哲学还直接决定了 Go 语言错误处理的形态:Go 语言采用了显式的基于值比较的错误处理方案,函数 / 方法中的错误都会通过 return 语句显式地返回,并且通常调用者不能忽略对返回的错误的处理。
组合:
Go 语言不像 C++、Java 等主流面向对象语言,我们在 Go 中是找不到经典的面向对象语法元素、类型体系和继承机制的,Go 推崇的是组合的设计哲学。
总之,组合原则的应用实质上是塑造了 Go 程序的骨架结构。类型嵌入为类型提供了垂直扩展能力,而接口是水平组合的关键,它好比程序肌体上的“关节”,给予连接“关节”的两个部分各自“*活动”的能力,而整体上又实现了某种功能。并且,组合也让遵循“简单”原则的 Go 语言,在表现力上丝毫不逊色于其他复杂的主流编程语言。
并发:
Go 放弃了传统的基于操作系统线程的并发模型,而采用了用户层轻量级线程,Go 将之称为 goroutine。
goroutine 占用的资源非常小,Go 运行时默认为每个 goroutine 分配的栈空间仅 2KB。goroutine 调度的切换也不用陷入(trap)操作系统内核层完成,代价很低。因此,一个 Go 程序中可以创建成千上万个并发的 goroutine。而且,所有的 Go 代码都在 goroutine 中执行,哪怕是 go 运行时的代码也不例外。
面向工程:
Go 语言设计的初衷,就是面向解决真实世界中 Google 内部大规模软件开发存在的各种问题,为这些问题提供答案,这些问题包括:程序构建慢、依赖管理失控、代码难于理解、跨语言构建难等。
在面向工程设计哲学的驱使下,Go 在语法设计细节上做了精心的打磨。
由于诞生年代较晚,而且目标比较明确,Go 在标准库中提供了各类高质量且性能优良的功能包,其中的net/http、crypto、encoding等包充分迎合了云原生时代的关于 API/RPC Web 服务的构建需求。
开发人员在工程过程中肯定是需要使用工具的,Go 语言就提供了足以让所有其它主流语言开发人员羡慕的工具链,工具链涵盖了编译构建、代码格式化、包依赖管理、静态代码检查、测试、文档生成与查看、性能剖析、语言服务器、运行时程序跟踪等方方面面。
总结:
Go 语言的设计哲学:简单、显式、组合、并发和面向工程。
- 简单是指 Go 语言特性始终保持在少且足够的水平,不走语言特性融合的道路,但又不乏生产力。简单是 Go 生产力的源泉,也是 Go 对开发者的最大吸引力;
- 显式是指任何代码行为都需开发者明确知晓,不存在因“暗箱操作”而导致可维护性降低和不安全的结果;
- 组合是构建 Go 程序骨架的主要方式,它可以大幅降低程序元素间的耦合,提高程序的可扩展性和灵活性;
- 并发是 Go 敏锐地把握了 CPU 向多核方向发展这一趋势的结果,可以让开发人员在多核时代更容易写出充分利用系统资源、支持性能随 CPU 核数增加而自然提升的应用程序;
- 面向工程是 Go 语言在语言设计上的一个重大创新,它将语言要解决的问题域扩展到那些原本并不是由编程语言去解决的领域,从而覆盖了更多开发者在开发过程遇到的“痛点”,为开发者提供了更好的使用体验。
这些设计哲学直接影响了 Go 语言自身的设计。理解这些设计哲学,也能帮助我们理解 Go 语言语法、标准库以及工具链的演化决策过程。