我觉得用概括性的叙述方式很难描述这篇文章的内容,因此本文将改用访谈形式进行阐述。
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》试图通过以下方式来消除诸多困惑。
-
首先强调基础概念与术语的讲解。若无法理解这些基础概念和术语,便很难充分掌握诸多规则与高阶概念。
-
书中新增了 “值的组成部分” 这一术语,并专门撰写了一篇文章来阐释值的组成部分。这篇文章揭示了部分类型的底层结构,以便 Go 开发者能更深入地理解这些类型的值。我认为,了解一些可能的底层实现方式,对于厘清各类 Go 值相关的困惑大有裨益。
-
书中对内存块进行了详细阐释。了解 Go 值与内存块之间的关联,对于理解垃圾回收器(GC)的工作原理以及如何避免内存泄漏,都大有帮助。
-
书中将接口值视为封装非接口值的 “盒子”。我发现,把接口值理解为 “值的盒子”,这对于厘清许多与接口相关的困惑非常有帮助。
-
书中澄清了 Go 语言规范中存在的若干模糊之处,例如嵌入规则、提升方法值的求值方式以及 panic/recover 机制等。
-
书中通过整合大量知识点与细节,撰写了若干总结性文章及专题文章,这能为 Go 开发者节省不少学习时间。
还有其他值得一提的内容吗?
本书并未深入探讨自定义泛型相关内容。若需学习自定义泛型,建议阅读《Go 泛型 101》(Go Generics 101)一书。
此外,在讲解类型转换、可赋值性及比较规则时,书中特意忽略了(在自定义泛型中频繁使用的)类型参数类型。换言之,本书并未考虑涉及自定义泛型的相关场景。