\
本章学习目标
- 了解Go与众不同的地方
- 了解如何访问Go Playground
- 学会将文本打印到屏幕上
- 对包含任意自然语言的文本进行实验
Go是一门为云计算而生的编程语言。包括亚马逊(Amazon)、苹果(Apple)、科能软件(Canonical)、雪佛龙(Chevron)、迪士尼(Disney)、脸书(Facebook)、通用电气(GE)、谷歌(Google)、Heroku、微软(Microsoft)、Twitch、威瑞森无线(Verizon)和沃尔玛(Walmart)在内的公司都使用了Go来开发重要的项目,并且由于诸如CloudFlare、Cockroach Labs、DigitalOcean、Docker、InfluxData、Iron.io、Let’s Encrypt、Light Code Labs、Red Hat CoreOS、SendGrid这样的公司以及云原生计算基金会(Cloud Native Computing Foundation)等组织的推动,许多Web底层基础设施正在陆续迁移至Go之上。
尽管Go正在数据中心大放异彩,但它的应用场景并不仅限于工作区域。例如,Ron Evans和Adrian Zankich就创建了用于控制机器人和硬件的Gobot库,而Alan Shreve则创建了以学习Go为目的的开发工具ngrok项目,并将该项目转变成自己的全职事业。
为了向图1-1所示的那只无忧无虑的Go吉祥物表示敬意,社区中的Go拥护者通常会把自己称为gopher(地鼠、囊地鼠)。虽然编程路上充满着各式各样的挑战,但通过使用Go并阅读本书,我们希望你能够从中发现编程的乐趣。
图1-1 Renée French设计的Go地鼠吉祥物
本章将展示一个运行在Web浏览器中的Go程序,并基于该程序进行一些实验。
请考虑这一点
像英语这样的自然语言充斥着各式各样模棱两可的话。例如,当你向数字助理说出“Call me a cab”的时候,它是应该帮你致电出租车公司,还是应该假设你想要把自己的名字改成“a cab”?
清晰度对于编程语言永远都是最重要的。假如编程语言的语法或者句法允许歧义存在,那么计算机也许就无法完成人们指定的行为,这样一来编程工作将变得毫无意义。
Go并不是一门完美的语言,但它在清晰度方面所做的努力远超我们之前用过的所有语言。在学习本章内容的时候,你将会看到一些名词缩写以及行业术语。虽然一开始你可能会对某些内容感到陌生,但我们希望你可以多花些时间,字斟句酌,仔细体会Go是如何减少语言中的歧义的。
1.1 什么是Go
Go是一门编译语言。在运行程序之前,Go首先需要使用编译器将用户编写的代码转换为计算机能够理解的0和1。为了便于执行和分发,Go编译器还会把所有代码整合并编译成一个单独的可执行文件。在编译的过程中,Go编译器能够捕捉到程序中包括拼写错误在内的一些人为失误。
并非所有编程语言都需要编译才能运行,如Python、Ruby和其他一些流行语言就选择了在程序运行的时候,通过解释器一条接一条地转化代码中的声明,但这也意味着bug可能会隐藏在测试尚未触及的代码当中。
不过换个角度来看,解释器不仅能够让开发过程变得迅速且具有交互性,还能够让语言本身变得灵活、轻松和令人愉快。相反,编译语言却常常因为像机器人一样顽固不化、墨守成规而广为人知,并且缓慢的编译速度也常常为人所诟病,然而实际上并非所有编译语言都是如此。
我们想要构造出这样一种语言,它不仅可以像C++和Java这类静态编译语言一样安全、高效,还可以像Python这类动态类型解释语言一样轻巧且充满乐趣。
——Rob Pike,Geek of the Week
Go在考虑软件开发的体验方面可谓煞费苦心。首先,即使是大型程序的编译也可以在极短的时间内完成,并且只需要用到一条命令。其次,Go语言排除了那些可能会导致歧义的特性,鼓励可预测和简明易懂的代码。最后,Go为Java等传统语言死板的数据结构提供了轻量级的替代品。
Java避免了C++当中许多不常见、难懂和令人迷惑的特性,根据我们的经验,这些特性带来的麻烦要比好处多得多。
——James Gosling,Java: an Overview
每一种新的编程语言都会对以往想法进行改良。与早期语言相比,在Go里面高效地使用内存将变得更为容易,出错的可能性也更低,并且Go还能利用多核机器上的每个核心获得额外的性能优势。很多成功案例都会把性能提升列举为转向Go的其中一个原因。例如,Iron.io只用了2台Go服务器就替换了他们原来使用的30台Ruby服务器;而Bitly在使用Go重写原有的Python应用程序之后也获得了持续、可测量的性能提升,这导致他们在之后把自己的C应用程序也“更新换代”成了相应的Go版本。
Go不仅像解释语言一样简单和有趣,还在性能和可靠性上占有优势,并且由于Go是一门只包含几种简单概念的小型语言,所以学习起来也相对较快。综上所述,我们得出以下Go箴言:
Go是一门开源编程语言,使用它可以大规模地生产出简单、高效且可信赖的软件。
——Go品牌手册
提示 当你在互联网上搜索Go的相关话题时,可以使用关键字golang来代表Go语言。这种将-lang后缀添加到语言名字之后的做法也适用于其他编程语言,如Ruby、Rust等。
速查1-1 Go编译器的两个优点是什么?
1.2 Go Playground
学习Go语言最快捷的方式就是使用Go Playground,这个工具可以让你在无须安装任何软件的情况下直接编辑、运行和试验Go程序。当你点击Go Playground中的Run(运行)按钮的时候,Go Playground就会在谷歌公司的服务器上编译并执行你输入的代码,然后在屏幕上显示执行代码的结果,如图1-2所示。
图1-2 Go Playground
点击Go Playground中的Share(分享)按钮可以获得一个访问当前代码的链接。你可以通过这个链接把自己的代码分享给朋友,或者将其用作浏览器书签以便保存工作进度。
注意 虽然本书列出的所有代码和练习都可以通过Go Playground执行,但如果你更习惯使用文本编辑器和命令行,那么你可以下载Go并安装到你的计算机上。
速查1-2 Go Playground中的Run按钮是用来做什么的?
1.3 包和函数
当我们访问Go Playground的时候将会看到代码清单1-1所示的代码,它作为学习Go语言的起点真的再合适不过了。
代码清单1-1 与Go Playground的初次见面:playground.go
package main ←--- 声明本代码所属的包import ( "fmt" ←--- 导入fmt(是format的缩写)包,使其可用)func main() { ←--- 声明一个名为main的函数 fmt.Println("Hello, playground") ←--- 在屏幕上打印出“Hello, playground”}
尽管这段代码非常简短,但它引入了package、import和func这3个非常重要的关键字,这些保留的关键字都有它们各自的特殊目的。
package关键字声明了代码所属的包,在本例中这个包的名字就是main。所有用Go编写的代码都会被组织成各式各样的包,并且每个包都对应一个单独的构想,例如,Go语言本身就提供了一个面向数学、压缩、加密、图像处理等领域的标准库。
在package关键字之后,代码使用了import关键字来导入自己将要用到的包。一个包可以包含任意数量的函数。例如,math包提供了诸如Sin、Cos、Tan和Sqrt等函数,而此处用到的fmt包则提供了用于格式化输入和输出的函数。因为在屏幕上显示文本是一个非常常用的操作,所以Go使用了缩写fmt作为包名。gopher通常把这个包的名字读作“FŌŌMT!”,给人的感觉仿佛这个库是使用漫画书上的大爆炸字体撰写的一样。
func关键字用于声明函数,在本例中这个函数的名字就是main。每个函数的体(body)都需要使用大括号{}包围,这样Go才能知道每个函数从何处开始,又在何处结束。
main这一标识符(identifier)具有特殊意义。当我们运行一个Go程序的时候,它总是从main包的main函数开始运行。如果main不存在,那么Go编译器将报告一个错误,因为它无法得知程序应该从何处开始执行。
为了打印出一个由文本组成的行,例子中的代码使用了Println函数(其中ln为英文line的缩写)。每次用到被导入包中的某个函数时,我们都需要在函数的名字前面加上包的名字以及一个点号作为前缀。例如,代码清单1-1中的Println函数前面就带有fmt后跟一个点号作为前缀,这是因为Println函数就是由被导入的fmt包提供的。Go的这一特性可以让用户在阅读代码的时候立即弄清楚各个函数分别来自哪个包。
当我们按下Go Playground中的Run按钮时,代码中被引号包围的文本将输出至屏幕,最终使得文本“Hello, playground”出现在Go Playground中的输出区域中。对英语来说,即使缺少一个逗号也有可能使整个句子的意义变得完全不同。同样,标点符号对编程语言来说也是至关重要的。例如,Go就需要依靠引号、圆括号和大括号等符号来理解用户输入的代码。
速查1-3
1.Go程序从何处开始执行?
2.fmt包提供了什么功能?
1.4 唯一允许的大括号放置风格
Go对于大括号{}的摆放位置非常挑剔。在代码清单1-1中,左大括号{与func关键字位于同一行,而右大括号}则独占一行。这是Go语言唯一允许的大括号放置风格,除此之外的其他大括号放置风格都是不被允许的。
Go之所以如此严格地限制大括号的放置风格,与这门语言刚刚诞生时出现的一些情况有关。在早期,使用Go编写的代码总是无一幸免地带有分号,它们就像迷路的小狗一样跟在每条单独的语句后面,例如:
fmt.Println("Hello, fire hydrant");
到了2009年12月,一群“忍者”gopher决定把分号从语言中驱逐出去。好吧,这么说也不太准确。实际上,Go编译器将为你代劳,自动地插入那些可爱的分号。这种机制运行得非常完美,但它的代价就是要求用户必须遵守上面提到的唯一允许的大括号放置风格。
如果用户尝试将左大括号和func关键字放在不同的行里面,那么Go编译器将报告一个语法错误:
func main( ←--- 函数体缺失{ ←--- 语法错误:在{之前发现了意料之外的分号或新行}
出现这个问题并不是编译器有意刁难,而是由于分号被插到了错误的位置,导致编译器犯了点儿小迷糊,最终才不得不求助于你。
提示 在阅读本书的时候,亲力亲为、不厌其烦地键入代码清单中的每段代码是一个不错的主意。这样一来,如果你键入了错误的代码,就会看到相应的语法错误,但这并不是一件坏事。能够识别、理解并纠正代码中的错误是一项至关重要的技能,而且坚持不懈也是一种宝贵的品质。
速查1-4
用户必须将左大括号{置于何处才能避免引起语法错误?
1.5 小结
- 通过Go Playground,我们可以在不必安装任何软件的情况下开始使用Go。
- 每个Go程序都由包中包含的函数组成。
- 为了将文本输出至屏幕,我们需要用到标准库提供的fmt包。
- 和自然语言一样,编程语言中的标点符号也是至关重要的。
- 到目前为止,我们已经使用了25个Go关键字中的3个,它们分别是:package、import和func。
为了检验你是否已经掌握了上述知识,请按照接下来展示的练习的要求修改Go Playground中的代码,并点击Run按钮来查看结果。如果你在做练习的过程中遇到麻烦无法继续下去,那么可以通过刷新浏览器来让代码回到最初的状态。
实验:playground.go
- 修改代码中被引号包围的文本,使得程序在将文本打印至屏幕时,可以用你的名字向你打招呼。
- 在main函数的函数体{}内添加第二行代码,使得程序可以打印出两个文本行。就像这样:fmt.Println("Hello, world") fmt.Println("Hello, 世界")
- Go支持所有自然语言的字符。你可以尝试让程序用中文、日文、俄文甚至是西班牙文打印文本。如果你不懂上述提到的这些语言,那么可以先通过谷歌翻译工具进行翻译,然后再把翻译后的文本复制/粘贴到Go Playground。
你可以通过点击Go Playground中的Share按钮来获得访问当前代码的链接,然后将该链接发布至本书的论坛与其他读者进行分享。
最后,你可以将你的解法和“习题答案”中给出的参考答案进行对比,从而判断其是否正确。
速查1-1答案 Go编译器可以在极短的时间内完成对大型程序的编译,并且它可以在程序运行之前找出代码中的一些人为失误,如拼写错误等。
速查1-2答案 Run按钮可以在谷歌的服务器上编译并执行用户输入的代码。
速查1-3答案
1.Go程序从main包的main函数开始执行。
2.fmt包提供了用于格式化输入和输出的函数。
速查1-4答案 左大括号必须与func关键字位于同一行而不是独占一行,这是Go语言唯一允许的大括号放置风格。