在笔者看来,Go是一种非常优雅和一致的语言。此外,它还提供了许多现代化的创新功能,使编程更有效、更可靠。此外,代码的可读性和可维护性也是它的设计特色。
这是我们将在本书后面讨论的提高效率的重要基础。与其他任何功能一样,优化总是会增加复杂性,因此修改简单的代码要比将已经复杂的代码复杂化更容易。即使是高效代码,简单、安全和可读性也是最重要的。请确保你知道如何在不考虑效率的情况下实现这一点!
如果你有兴趣了解更多相关内容,实践是最佳途径。如果你需要在我们开始优化之前获得更多经验,这里有一份简短的优秀资源列表:
· “Effective Go”( https://oreil.ly/9auky )
· “How to Write Go Code”( https://oreil.ly/uS51g )
· “A Tour of Go”( https://oreil.ly/LpGBN )
· Maximilien Andile的《Practical Go Lessons》( https://oreil.ly/VnFms ),它有免费数字版
· 为Go中的任何开源项目做出贡献,例如,参加我们每年提供4次或更多次的CNCF指导计划( https://oreil.ly/Y3D2Q )
Go优化、基准测试和效率实践的真正威力来自日常编程中的实际应用。因此,希望你能够将效率与其他有关可靠性或抽象的良好技术相结合,以供实际使用。虽然有时必须为关键路径构建完全定制的逻辑(正如你在第10章中看到的那样),但基本的、通常足够好的效率来自对简单规则和语言能力的理解。这就是我在本章中重点介绍Go及其功能的原因。有了这些知识,我们就可以进入第3章,学习如何在需要时提高程序执行效率和整体性能。
[1] 用于小型设备上编写Go的新框架正在出现,例如,GoBot( https://gobot.io )和TinyGo( https://tinygo.org )。
[2] 这是一个有争议的话题。在基础设施行业中,对于配置即代码的高级语言有一场激烈的争论,例如,HCL、Terraform、Go模板(Helm)、Jsonnet、Starlark和Cue。在2018年,我们甚至开源了一个用Go编写配置的工具,叫作“mimic”( https://oreil.ly/FNjYD )。可以说,用Go编写配置的最大争议是它感觉太像“编程”并且要求系统管理员具备编程技能。
[3] WebAssembly旨在改变这一点,但不会很快( https://oreil.ly/rZqtp )。
[4] 类似的不满促使谷歌的另一部分工程师在2022年创建了另一种语言——Carbon( https://oreil.ly/ijFPA ),但它的目标与Go不同,从设计上讲,它更注重效率,并专注于熟悉C++概念和互操作性。因此,让我们看看如何使用Go才能追上Carbon!
[5] 一个值得注意的例子是依赖管理工作的争议( https://oreil.ly/3gB9m )。
[6] 当然,在各处也有一些不一致之处,这就是为什么社区创建了更严格的formatters( https://oreil.ly/RKUme )、linters( https://oreil.ly/VnQSC )或风格指南( https://oreil.ly/ETWSq )。然而,标准工具就足以让每个Go代码库都令人满意了。
[7] 有一个例外:单元测试文件必须以 _test.go 结尾。这些文件可以具有相同的包名或<package name> test格式的名称,从而可以模仿包的外部用户。
[8] 标准库是指与Go语言工具和运行环境代码一起提供的包。通常只提供成熟、核心的功能,因为Go有强大的兼容性保证。Go还维护着一个实验性的模块——golang.org/x/exp( https://oreil.ly/KBTwn ),其中包含了有用的代码,这些代码必须经过验证才能被纳入标准库中。
[9] 虽然Go每天都在改进,但有时你可以添加更高级的工具来进一步提升开发体验,例如goimports( https://oreil.ly/pS9MI )或bingo( https://oreil.ly/mkjO2 )。在某些领域,Go不能固执己见,并且受到稳定性保证的限制。
[10] CAP原则( https://oreil.ly/HyBdB )提到了一个严肃对待失败的极好例子。它声明你只能从三个系统特征中选择两个:一致性、可用性和分区容错性。系统一经发布,就必须处理好网络分区(通信故障)。作为一种错误处理机制,你可以将系统设计为等待(搁置可用性)或对部分数据进行操作(搁置一致性)。
[11] bash有很多错误处理方法( https://oreil.ly/Tij9n ),但默认值是隐式的。程序员可以选择打印或检查${?},它保存了任何给定行之前执行的最后一个命令的退出代码。退出码为0表示命令已执行且没有任何问题。
[12] 这种断言模式在其他第三方库中也很典型,例如流行的testify包( https://oreil.ly/I47fD )。但是笔者不喜欢testify包,因为有太多方法可以做同样的事情。
[13] 将代码转换为实际的机器可理解代码之前会发生许多事情,比如将Java中的程序编译成Java字节码。这个过程非常复杂,普通人无法理解,因此机器学习“AI”工具被发明出来,( https://oreil.ly/baNvh )用来自动调整JVM。
[14] 2020年的一项调查( https://oreil.ly/WrtCH )显示,在被使用最多的10种编程语言中,2种强制面向对象编程(Java、C#),6种支持OOP,2种没有实现OOP。对于在数据结构或函数之间必须超过3个变量的上下文的算法,笔者总是更喜欢面向对象编程。
[15] 相比于方法而言( https://oreil.ly/Et9CE ),笔者更喜欢函数,因为它们在大多数情况下更易于使用。
[16] PlanetScale的博客文章( https://oreil.ly/ksqO0 )对摘要进行了很好的解释。
[17] 举几个公开进行变更的案例,比如Salesforce( https://oreil.ly/H3WsC )、AppsFlyer( https://oreil.ly/iazde )和Stream( https://oreil.ly/NSJLD )。
[18] 例如,当我们查看一些基准测试( https://oreil.ly/s7qTj )时,会发现Go有时比Java快,有时比Java慢。然而,如果我们看一下CPU负载,Go或Java每次都更快。原因很简单,例如,其实现允许更少的CPU周期浪费在内存访问上。任何编程语言都能做到这一点。问题是,实现这一点有多难?我们通常不会衡量在每种特定语言中优化代码花了多少时间,以及在优化后阅读或扩展这些代码的难易程度等。但只有这些指标才会告诉我们哪种编程语言“更快”。