02|拒绝“Hello and Bye”:Go语言的设计哲学是怎么一回事?
该思维导图由 AI 生成,仅供参考
- 深入了解
- 翻译
- 解释
- 总结
Go语言的设计哲学体现了其五大设计原则:简单、显式、组合、并发和面向工程。首先,Go语言以简单为设计原则,致力于打造一门简单的编程语言,拒绝了语言特性融合的道路。其次,Go语言强调显式,要求开发人员明确进行类型转换和错误处理,提高了代码的可读性和可靠性。在组合方面,Go语言采用了类型嵌入和接口的水平组合方式,实现了垂直扩展和能力委托,塑造了程序的骨架结构。并发是Go语言的重要设计原则之一,采用了轻量级的goroutine和内置的channel和select,降低了开发并发程序的心智负担,同时也使得程序设计更适应现代计算环境。面向工程是Go语言的另一设计原则,它致力于解决真实世界中大规模软件开发存在的各种问题,包括程序构建慢、依赖管理失控、代码难于理解、跨语言构建难等。Go语言在语法设计、工具链与标准库的设计上考虑了解决工程问题,提供了丰富的工具链和自带电池的标准库,为开发者提供了更清晰、更可靠的编程体验,提升了生产效率。 Go语言的设计哲学直接影响了其语法、标准库以及工具链的演化决策过程,为开发者提供了更好的使用体验。
《Tony Bai · Go 语言第一课》,新⼈⾸单¥59
全部留言(37)
- 最新
- 精选
- 自由Tony Bai 老师,你好,例举两个我认为复合 Go 语言设计哲学的例子,我的技术能力捉襟见肘,说的不对地方还希望老师斧正。 一、异常处理 Go 语言核心开发者 Dave 曾说过 “You only need to check the error value if you care about the result”,在我们不处理错误的时候,我们不应该对它的返回值抱有任何幻想。 Go 的异常处理逻辑,没有引入 exception,而是使用了多参数返回,在返回中带上错误,由调用者来判定这个错误。 - 简单 - 没有隐藏的控制流 - 完全交给你控制 error - 考虑失败,而不是成功 二、类型别名 在特定情况下,帮助代码逐步修复。 类型别名的存在,是 渐进式代码修复(Gradual code repair) 的关键,什么是渐进式代码修复?举一个🌰 重构。重构代码,我们当然希望重构后的好处,能够适用于所有代码,但是,重构的好处与代价是成正比的,往往一次重构会伴随着大量的修改,随着代码量越来越大,一次完成所有修改变得不可行。修复需要逐步完成。在代码量少时,我们可以一次性完成所有的修复,这样的修复被称为原子代码修复(atomic code repair),它的概念很简单,就是在一次提交中,更新所有的因为重构带来的问题修复,但是概念的简单会被实际的复杂性抵消,一次提交可能非常大,大的提交很难去一次性修复,出现问题也很难去溯源,最重要的是,可能会与其他同学的工作产生冲突,例如某个同学,在工作时,使用了旧的 API,合并代码时,并不会产生冲突,而我的提交错过了它的引用。 因此,我们需要一个过渡期,这个过渡期就是为了逐步替换,也就是渐进式代码修复,将旧的引用,逐步替换,同时将旧的换为新的,这就是渐进式代码修复,它的缺点是比原子代码修复的工作量更大,但是它更容易提交、审查,并且保证了,没有人引用后再删除旧的类型别名。
作者回复: 👍。说的很好。很认同你提到的基于“类型别名”的渐进式代码修复(Gradual code repair) 思路。这也是类型别名最初被引入go的初衷(https://github.com/golang/proposal/blob/master/design/18130-type-alias.md)。我觉得它也是go面向工程设计哲学的体现。另外type alias在基于现有实现进行扩展并做出新的封装方面也有“奇效”。
2021-10-15640 - 王智表示身为一名Java工程师,在看到组合的时候有一点疑惑,我的想法是这里的组合就是将另一个类里面的东西平移过来,类似于java中的继承,我想问的是如果存在两个类包含相同名字的方法或者属性,这个go怎么处理?还是直接就不允许呢?go语言从来没接触过,不懂就问
作者回复: 好问题! go的组合有多种形式。按你提到的“继承”型组合中,如果组合的两个类型中有相同名字的字段,那怎么解决呢?看下面中的例子: package main type T1 struct { a int } type T2 struct { a int } type T struct { T1 T2 } func main() { var t T // t.a = 5 // 编译报错:ambiguous selector t.a t.T1.a = 5 t.T2.a = 6 println(t.T1.a) // 5 println(t.T2.a) // 6 } 如果T组合的两个类型T1和T2都包含字段a,那么我们不能直接使用t.a,而是通过t.T1.a和t.T2.a分别指代各自类型中的字段a。
2021-10-26627 - 罗杰21 世纪的 C 语言,的确实至名归。依然有几个小问题:1. Go 有 GC,我们使用 Go 来开发后端的所有服务,有个 PVP 的服务,需要逐帧计算客户端上报的结果是否正确,此时对于内存的分配就要特别小心,开发起来很不顺畅。是否这种服务的性质不太合适使用 Go 来开发;2. 有人吐槽 Go 核心人员不想做的东西,就是 Less is more,自己想做就是各种哲学,这个问题,老师怎么看?
作者回复: 罗杰出品的问题,都是精品问题^_^。 先来看第一个问题,Go最初设计目标是通用的系统编程语言,但Go选择支持了GC。Go的GC虽然在go团队的努力下,开销越来越小,但开销小,低延迟不代表没有,这就决定了Go在一些对性能极其敏感的领域可能并不是最好的选择。你的问题中也提到了pvp服务,想必你们也是采用了面向服务的架构,这种架构本身就是可以天然适合技术异构的。如果觉得不妥,也别强求,果断换非GC语言,比如c、c++或是rust。如果说非要坚持用go来完成,那么说明你是go的骨灰粉,在解决问题的过程中,你也会完成一次go技能的升华。 第二个问题,Go语言的简单或者说功能特性少,的确来自与less is more的理念。保持一门小语言,让语言更容易学习与理解。同时每个特性都是经过精心打磨与实现,不能再少了。上周我看了rob pike最新一期的talk,他还在说 “Go语言中变量声明的方式有些多了”,这也是我在实际编码过程中的体会。如果重新来过,我想rob pike会更彻底的执行less is more,将变量声明方式再减少一种。所以说,特性少不是不想做,而是经过深思熟虑,那个特性的确没必要加入到语言中。
2021-10-15717 - liaomarsgo的异常处理,使用起来简单,但是不方便,请问老师这是在践行go的简单设计哲学吗?
作者回复: 从go设计者的初衷来看(https://golang.google.cn/doc/faq#exceptions),go没有采用像java那样的结构化异常处理的确是出于对“简单”原则的考虑。 在java中错误处理与真正的“异常”是混杂在Try-catch机制中的,并没有明显的界限,无论是错误还是异常,一旦throw,方法的调用者就得负责处理它。 但在go中,错误处理与真正的异常处理是严格分开的,也就是说不要将panic掺和到错误处理中。 错误处理是常态,go中只有错误是返回给上层的。一旦出现panic,这意味着整个程序处于即将崩溃的状态,返回给上层几乎也是“无济于事”,所以在go中,一个常见的api设计思路是 不要向外部抛出panic(don't panic!)。如果api中存在panic的可能性,那么api自己要负责处理panic,并通过error将状态返回给上层。如果api无法处理panic,那程序就很大可能是要崩溃了,这种panic多是因为程序bug导致的。
2021-10-15916 - Geek_399042自动加入分号是不是也是简单的设计哲学呢,能让编译器做的事不需要交给开发者。
作者回复: 手动点赞
2021-10-15212 - 张申傲尤其认同 Go 语言的“面向工程”这一设计哲学。作为 Java 的资深用户,每天都深受编译速度慢、依赖树失控、代码风格不统一等问题的困扰。Go 语言的设计哲学恰恰迎合了现代大规模业务系统的开发和维护。
作者回复: 👍
2021-12-0139 - 悟二空只有 TonyBai 老师的这门专栏课,我会把每条留言评论都认真看完,因为老师都有很认真的在回复,一点儿也不含糊。能学到非常多的知识,非常感谢老师,我一定能学好Go语言并进入自己想去的公司的。
作者回复: 💪
2022-04-276 - 运维夜谈老师,请教两个问题: 1、文中提到的正交独立是什么意思?不是很理解。 2、Go不支持面向对象,那意味着复用性不好,这种后面老师会讲工程实践吗?
作者回复: 1. 正交(orthogonality)是从几何学中引入的术语,如果两条线以直角相交,如图形上的轴线,就是正交的。如果说两个事物是正交的,那么我们说 这两个事物是独立且解耦的,一个事物的变化不影响另外一个事物。 我们经常用“正交”来评价一个系统的设计,比如在一个设计良好的系统中,数据库代码将与用户界面正交:你可以在不影响数据库的情况下,独>立进行界面的演进。 编程语言的语法元素间也存在着正交的情况,比如文中提到的类型定义与方法是正交的。这意味着一个类型可以有方法,也可以没有方法。而方>法本质上接收类型作为其第一个参数的函数而已(具体参考第24讲)。 在Go语言中,正交的语法还有一些,比如接口就与Go语言其他部分是正交的。 但正交的两个语法特性组合起来可以实现其它特性,这也是我们在一个系统中经常做的事情。 2. 难道不用面向对象就不能复用了么?:) Go有自己的组合的设计哲学,组合也可以实现复用。课程后面会有讲解。
2021-12-1156 - 迷途书童Go语言的设计哲学有什么权威出处吗?还是老师自己总结的?
作者回复: 自己总结的。但也依据了go核心团队的一些talk中的内容以及个人对go的理解。
2022-06-243 - Holygo底层代码深入发现了很多巧妙的地方, defer+panic简单使用,里面的实现不一般 内存管理多级缓存快速减少锁,为GC埋下众多伏笔, Mutex兼顾公平 GMP模式实现等等, 每个版本迭代,持续进化(GOPHER坐享其成)
作者回复: 👍
2022-04-183