由Alan A. A. Donovan与Brian W. Kernighan共同编著的新书《Go编程语言》(Go Programming Language)对Go这门语言进行了一次精彩的介绍。本书涵盖了包括Go语言于2015年8月所发布的最新稳定版本1.5中的内容。读者应当具备类C或Python风格语言的编程经验,但并不限定于具体某种语言。由于Go是一种编译型的类型化语言,因此,具有这方面编程经验的开发者与偏重于脚本语言或非类型语言的开发者相比,这门语言的学习曲线将显得不那么陡峭。
本书的前半部分涵盖了Go编程语言的基础,包括源文件的格式与Unicode编码、变量、值类型,以及结构体、Map、数组以及Slice等等。前半部分的结尾描述了Go语言的异常处理机制Panic与Recover。
本书的下半部分专注于在Go语言中独树一职的一些特性:不用继承而实现面向对象编程、隐式接口实现,当然还有通过协程(goroutine)实现并发编程。本书的结尾部分讲述了一些实用的打包技巧、如何使用标准的Go工具进行测试,以及关于反射及非安全代码的参考。
整本书中所介绍的示例都提供了相应的代码(可在本书的官网上下载),也就是说可以通过以下命令(在Linux系统上)运行示例代码:
$ export GOPATH=$HOME/gobook # choose workspace directory
$ go get gopl.io/ch1/helloworld # fetch, build, install
$ $GOPATH/bin/helloworld # run
对于在其他类型的系统中使用Go的读者来说,他们必须对示例代码进行一些调整。比方说要将GOPATH的设置方式变为set GOPATH=“%HOMEPATH%\gobook”,并通过调用%GOPATH%\bin\helloworld的方式运行。
本书的第一章(可在本书的官网上免费下载)就表现出了本书的风格,并且在本书的文字之间提供了丰富的示例,这样的风格一直延续到了本书的结尾。
第一章本身的内容进展很快,从如何通过类似于uniq这样的Unix工具的实现运行经典的“hello world”示例开始,一直讲到如何生成活动的Lissajous图形、并通过一个HTTP服务返回该图形。由于Go是由Google推出的语言,因此在网络应用示例部分还介绍了并发式web爬虫的概念。
虽然第一章名为“指南”,但读者可能会发现略过Lissajous图形示例(与网络应用示例)或许是种更好的做法,尤其是对于那些没有数学背景的读者来说。好在这些示例仅仅是本书之后将涵盖的内容的一部分样本,等读者阅读到后面这部分时,应该能够更轻松地理解它。当读者对于这门语言有更多的理解之后,这篇指南章节的后半部分应当显得较容易理解。
除了在本书的文字之间提供了大量的示例之外,每一小节通常还为读者提供了大量的练习交由读者完成,因为通过动手实践进行学习的方式比起仅仅通过阅读进行学习更有效得多。在练习之后还提供了大量的挑战内容,要求读者逐步完成更复杂的任务,以加深对这门语言的理解。
本书第二章的开头部分介绍了Go语言的命名规范,不过对于公共可见的标识符(以大写字母开头)与私有可见的标识符(以小写字母开头)之间的区别没有进行清晰地说明。有经验的Go语言用户自然了解这一标准,但习惯快速翻阅的读者却很可能会忽略这一细节,而两者所产生的效果的差别直到下一章关于包的部分才会真正讲到。
虽然有些瑕疵,但本书也为读者提供了许多良好的建议,包括如何处理错误(在检测到错误时选择速错,以避免错误的积累),以及如何使用defer注册用于清理功能的处理函数,这在释放互斥体锁时尤其实用。本书不仅仅只触及了Go语言的基础内容,整本书到处可见作者的真知灼见。特别值得一提的是如何在Go的for循环中处理捕获变量(captured variable),由于变量的作用域所限,必须在内部重新定义一个变量,使它具有一个不同的作用域:
for _, dir := range tempDirs() {
dir := dir // NOTE: necessary!
// …
}
本书对于类型、结构体以及函数(function)和方法(method)进行了着重描述,因为这些元素的创建与用法与其他语言有所不同。 本书提到在创建方法时可以指定Receiver类型,可选择值类型或是引用类型,并能够在其中使用除this/self之外的自定义名称。在使用接口的时候,类型或结构体可以隐式地满足某个接口的定义,对于空的接口类型来说,任何值都可以满足该接口。本书在介绍接口的部分特意涵盖了关于错误的更多细节,因为在Go语言中的错误都是以接口的形式表现的。
如果对于这本《Go编程语言》的评论缺少了Go语言中独一无二的特性:协程与管道(channel),它就不能算是一篇完整的书评。本书用了65页、即相当于本书20%左右的篇幅描述了如何使用协程(异步调用函数)、以及如何通过固定大小(缓冲)的管道或通过异步方式(无缓冲)实现协程之间的相互通信。在介绍如何使用管道发送简单的信号时,本书为读者展示了两种选择,一是将管道的闭包作为一种触发器以执行某些行为,二是通过发送标记符号数据(通常会包括一个布尔值、一个整数值、或仅仅是一个空结构而已)以实现相同的效果。除此之外,本书也展示了如何通过使用多路复用选择器,在多个管道间进行信号的获取或发送。
本书着重强调了使用互斥体(mutex)进行数据保护的重要性,它不仅能够避免数据竞态条件问题,同时也强调了在某些平台中,硬件本身需要在程序中加入一道强闸,以避免出现由于代码顺序被更改或者缓存行的共享造成程序产生不一致结果的问题。本书描述了多种不同的锁机制(例如简单的互斥体或读写锁),并且给出了每种不同实现方式的性能数据对比。
本书所介绍的几个协程为读者展现了如何进行某些场景下的HTTP处理,包括来自于多个客户端的网络连接,以及执行多线程的web连接的抓取。在这几个章节的结尾部分,作者介绍了一个基于客户端/服务器结构的聊天网络的示例,聊天消息可以在多个客户端之间进行路由,并且能够将资源的消耗降至最低。
本书还为读者介绍了如何使用go get工具实现包的获取,以及go test这个测试工具的使用,此外还介绍了CPU、内存或互斥体的性能诊断工具。最后,本书对于非安全代码以及反射包进行了简单的介绍,并对于这些特性的应用提出了适当的警告:如无必要,请不要使用他们。
在《Go编程语言》一书的出版商Addison Wesley的网站上可以购买本书的电子版,也可以在分销商那里购买实体书籍。
Alan Donovan是就职于Google基础设施部门的一位主管工程师,专攻软件开发工具。从2012年之后,他开始加入Go团队,负责静态分析库与工具的设计。他同时也是oracle、godoc-analysis、eg以及gorename等工具的作者。
Brian Kernighan在2000年之前就职于贝尔实验室的计算机科学研究中心,当时他负责为Unix开发语言与工具。他目前在普林斯顿大学的计算机科学系担任教授一职。他同时也是多本技术书籍的合著者之一,包括《C程序设计语言》以及《程序设计实践》。
查看英文原文:Book Review: The Go Programming Language