关于Go 101

43 阅读7分钟

我觉得用概括性的叙述方式很难描述这篇文章的内容,因此本文将改用访谈形式进行阐述。

Hi Tapir, 你计划何时撰写这本书?又是什么原因促使你有了这个想法呢??

大约在 2016 年 7 月,我使用 Go 语言已有两年时间(期间使用强度不算高),当时觉得 Go 是一门简单的语言,自己已经掌握了 Go 编程。那时我还收集了很多 Go 编程相关的细节知识,于是就想把这些细节整理成一本书,并且认为这应该是件不难的事。

我错了,当时太自负了。在尝试解释某些细节时,我发现自己根本无法把它们说清楚。随着困惑越来越多,我才意识到自己的 Go 语言知识如此有限,原来我还只是个 Go 编程新手。

我当时放弃了写那本书。

放弃了?可这本书现在不是已经写完了吗?

当时搁置的是那本书,并非《Go 101》。后来,我通过阅读大量 Go 语言官方文档和网上各类相关文章,还在一些 Go 语言论坛以及 Go 项目的 issue 追踪平台上寻找答案,最终几乎解决了所有困惑。

我花了大约一年时间才理清这些困惑。在此期间,每当我搞懂某个主题下的大部分疑问,重新找回能把这个主题讲清楚的信心时,就会针对该主题写一篇博客文章。到最后,我已经写了约 20 篇关于 Go 语言的文章,而且收集到的 Go 语言细节也比之前更多了。这时,重启编写 Go 语言书籍的计划,就提上了日程。

我又写了 10 篇基础教程类文章,以及 20 篇涵盖 Go 语言其他各类主题的文章。所以现在,《Go 101》(这本书的内容)已经包含大约 50 篇文章了。

你过去的困惑是什么?

我的部分困惑集中在一些语法和语义的设计细节上,有些则涉及特定类型(主要是切片、接口和通道)的值的相关问题,还有少数困惑与标准库包的 API 有关。

你认为自己过去那些困惑的成因是什么?

认为 Go 语言容易掌握,这种想法其实是有害的。持有这样的观点(即认为 Go 语言容易掌握)会让你对 Go 的理解停留在表面,进而阻碍你真正精通这门语言。

Go 语言是一门功能丰富的语言。它的语法集规模确实不算庞大,但也绝不能说小。Go 语言中的部分语法和语义设计十分直观,但也有一些设计略显反直觉,或是与其他设计存在不一致之处。此外,Go 的语法与语义设计中还包含若干权衡取舍,而开发者需要具备一定的 Go 编程经验,才能理解这些取舍背后的考量。

Go 语言提供了几种作为 “一等公民” 的非基础类型。在实现这些类型的过程中,开发者对其进行了封装处理,以此隐藏它们的内部结构。一方面,这种封装为 Go 语言编程带来了诸多便利;但另一方面,它也为更深入理解这些类型的值的行为特性设置了一些障碍。

许多官方及非官方的 Go 语言教程内容都十分浅显,它们往往只涵盖一些常规使用场景,却忽略了大量细节。从一方面来说,这或许有助于鼓励 Go 语言新手学习和使用 Go;但从另一方面来看,这也会让很多 Go 开发者对自己的 Go 语言知识掌握程度产生过度自信。

一些标准库包中声明的函数和类型并没有详尽的说明。这一点是可以理解的,因为许多细节极其微妙,很难找到恰当的措辞来清晰阐释。与其说一大堆不准确的话,不如用几句精准的表述来得好。但这确实给这些包的使用者留下了一些困惑。

那你认为 “简洁” 并非 Go 语言的卖点吗?

我认为,至少 “简洁” 并非 Go 语言的主要卖点。毕竟,还有其他好几门语言比 Go 更简洁。但另一方面,作为一门功能丰富的 Go 语言也并非一门复杂的语言。只要态度端正,新手程序员一年内就能掌握 Go 编程。

那你认为 Go 语言的卖点是什么呢?

就我个人而言,我认为 Go 语言作为一门静态类型语言,却能拥有许多动态脚本语言那样的灵活性 —— 这一点是它的主要卖点。

节省内存、程序启动快、代码执行速度快,再加上编译速度快,这几点结合起来是 Go 的另一个主要卖点。虽然这是许多 C 家族语言共有的卖点,但在 Web 开发领域,同时具备这四个特性的语言并不多见。事实上,这也是我从 Java 转向用 Go 做 Web 开发的主要原因。

内置的并发编程支持同样是 Go 的一个卖点,不过我个人认为这并非它的主要卖点。

出色的代码可读性是 Go 的又一个重要卖点。我感觉在 Go 的设计过程中,可读性是被考量的最重要因素。

良好的跨平台支持也是 Go 的一个卖点,尽管如今这个卖点已不算特别独特。

稳定的核心设计与开发团队,再加上活跃的社区,这两者共同构成也可以算作是 Go 的一个卖点。

《Go 101》是如何消除这些困惑的呢?

《Go 101》试图通过以下方式来消除诸多困惑。

  1. 首先强调基础概念与术语的讲解。若无法理解这些基础概念和术语,便很难充分掌握诸多规则与高阶概念。

  2. 书中新增了 “值的组成部分” 这一术语,并专门撰写了一篇文章来阐释值的组成部分。这篇文章揭示了部分类型的底层结构,以便 Go 开发者能更深入地理解这些类型的值。我认为,了解一些可能的底层实现方式,对于厘清各类 Go 值相关的困惑大有裨益。

  3. 书中对内存块进行了详细阐释。了解 Go 值与内存块之间的关联,对于理解垃圾回收器(GC)的工作原理以及如何避免内存泄漏,都大有帮助。

  4. 书中将接口值视为封装非接口值的 “盒子”。我发现,把接口值理解为 “值的盒子”,这对于厘清许多与接口相关的困惑非常有帮助。

  5. 书中澄清了 Go 语言规范中存在的若干模糊之处,例如嵌入规则、提升方法值的求值方式以及 panic/recover 机制等。

  6. 书中通过整合大量知识点与细节,撰写了若干总结性文章及专题文章,这能为 Go 开发者节省不少学习时间。

还有其他值得一提的内容吗?

本书并未深入探讨自定义泛型相关内容。若需学习自定义泛型,建议阅读《Go 泛型 101》(Go Generics 101)一书。

此外,在讲解类型转换、可赋值性及比较规则时,书中特意忽略了(在自定义泛型中频繁使用的)类型参数类型。换言之,本书并未考虑涉及自定义泛型的相关场景。