Go语言趣学指南

978-7-115-53142-1
作者: [加] 内森•扬曼(Nathan Youngman)[英] 罗杰•佩珀(Roger Peppé)
译者: 黄健宏
编辑: 杨海玲

图书目录:

详情

本书是一本面向Go语言初学者的书,循序渐进地介绍了使用Go语言所必需的知识,展示了非常多生动有趣的例子,并通过提供大量练习来加深读者对书中所述内容的理解。本书共分8个单元,分别介绍变量、常量、分支和循环等基础语句,整数、浮点数和字符串等常用类型,类型、函数和方法,数组、切片和映射,结构和接口,指针、nil和错误处理方法,并发和状态保护,并且每个单元都包含相应的章节和单元测试。 本书适合对初学Go语言有不同需求的程序员阅读。无论是刚开始学习Go语言的新手,还是想要回顾Go语言基础知识的Go语言使用者,只要是想用Go做开发,无论是开发小型脚本还是大型程序,本书都会非常有帮助。

图书摘要

版权信息

书名:Go语言趣学指南

ISBN:978-7-115-53142-1

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

著    [加]内森•扬曼(Nathan Youngman)

     [英]罗杰•佩珀(Roger Peppé)

译    黄健宏

责任编辑 杨海玲

人民邮电出版社出版发行  北京市丰台区成寿寺路11号

邮编 100164  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

读者服务热线:(010)81055410

反盗版热线:(010)81055315


Original English language edition, entitled Get Programming with Go by Nathan Youngman and Roger Peppé published by Manning Publications Co., 209 Bruce Park Avenue, Greenwich, CT 06830. Copyright © 2018 by Manning Publications Co.

Simplified Chinese-language edition copyright ©2020 by Posts & Telecom Press. All rights reserved.

本书中文简体字版由Manning Publications Co.授权人民邮电出版社独家出版。未经出版者书面许可,不得以任何方式复制或抄袭本书内容。

版权所有,侵权必究。


本书是一本面向Go语言初学者的书,循序渐进地介绍了使用Go语言所必需的知识,展示了非常多生动有趣的例子,并通过提供大量练习来加深读者对书中所述内容的理解。本书共分8个单元,分别介绍变量、常量、分支和循环等基础语句,整数、浮点数和字符串等常用类型,类型、函数和方法,数组、切片和映射,结构和接口,指针、nil和错误处理方法,并发和状态保护,并且每个单元都包含相应的章节和单元测试。

本书适合对初学Go语言有不同需求的程序员阅读。无论是刚开始学习Go语言的新手,还是想要回顾Go语言基础知识的Go语言使用者,只要是想用Go做开发,无论是开发小型脚本还是大型程序,本书都会非常有帮助。


跟本书的相遇,纯属偶然。

2018年6月下旬的一个晚上,我从外面散步后回家,坐在阳台上享受着初夏的微风,其间百无聊赖地拿起手机刷起了朋友圈,发现杨海玲编辑正在为本书招募译者。

我非常喜欢Go语言,并且一直对这门语言保持关注。尽管之前已经翻译过《Go Web编程》一书,但我还是常常期待有机会可以再次翻译Go语言方面的书。因此,当我看到出版社正在为本书寻找译者的消息时,我马上有预感,觉得自己的愿望就要实现了。

果不其然,当我在Manning出版社的网站上快速地浏览了本书的相关信息并且试读了公开的章节之后,我强烈地感受到这是一本非常有趣的Go语言的书,并且我深信,本书凭借优质的内容,将在未来的Go语言入门读物中占有一席之地。

简单来说,如果我想要再次翻译一本Go语言的书,毫无疑问就应该是这一本!在打定主意之后,我就向杨海玲编辑表达了想要翻译本书的意向,并在之后顺利地成为了本书的译者。

Go作为一门广受关注的热门语言,在市场上从来不缺少相关的书,特别是面向初学者的书。然而,跟市面上很多声称是入门书却只会一股脑儿地将各种语言细节硬塞给读者的“伪入门书”不一样,本书是一本真正面向初学者的书。整本书的学习曲线非常平缓,不会像过山车那样忽高忽低。书中的内容首先从变量、循环、分支、类型等基础知识开始,逐渐进阶至函数、方法、收集器和结构,最后再深入到指针、错误处理和并发等高级特性。只要翻开本书一页页读下去,你就会循序渐进地学到越来越多Go语言的知识,并且逐步掌握Go语言的众多特性。

除上面提到的优点之外,本书还是一本非常有趣的书。作者在书中列举了大量跟天文以及航天有关的例子,读者不仅要计算从地球乘坐宇宙飞船航行至火星所需的天数,还要在火星上放置探测器以便查找生命存在的痕迹,甚至还要想办法改造火星,使它能够适宜人类居住。值得一提的是,书中很多地方都带有可爱的地鼠(gopher)插图,它们就像旅行途中优美的景色一样,将为我们的学习旅途增添大量的乐趣。

总而言之,这是一本既有趣又实用的Go语言入门书。如果你只想读一本关于Go语言的入门书,那么我强烈推荐你读这一本。

回想当初,自己在通过阅读图书学习编程的时候,总是希望能够成为译者,拥有属于自己的翻译作品。然而,在实际成为译者之后才明白,原来翻译并不是一件简单的事情,它考验的不仅仅是译者的语言能力、文字能力和技术能力,还要求译者有足够的耐心和锲而不舍的精神。

具体到本书,在遣词造句方面虽然没有太多难懂的地方,但是在内容中使用了大量有趣的例子,如搭乘太空飞船前往火星、计算人类在火星上的体重和年龄、调查火箭发射事故、在火星上放置探测器、组建地鼠工厂等。如何在译文中准确无误地表达原文的意思并且保持原文的趣味性就成了本次翻译要面对的一大挑战。换句话说,译文不仅要保持原文的“形”,还要兼顾原文的“神”,只有做到“形神兼备”才行。为此,我在这方面用了足够多的时间也花了足够多的功夫,我有信心,大家在阅读本书的时候能够感受到跟原著一样的趣味性。

除书中有趣的例子之外,本书翻译的另一个难点在于例子中涉及的大量外部知识,特别是跟天文、航天有关的知识,如地球和火星之间的距离、用光速到达火星所需的时间、火星上各个着陆点的名字,等等。为了能够正确地翻译这些知识,我通常会先在维基百科网站上查找并且验证相关的信息,然后再进行翻译。曾经有一段时间,我的浏览器上面打开的都是与天文、航天相关的维基页面,甚至让我产生了一种自己在NASA上班的错觉(笑)。

花了不少时间,本书终于翻译完成。今后如果有机会的话,我大概还会继续进行翻译工作。希望在不远的将来,当读者在译者一栏看到“黄健宏”这个名字的时候,能够像看到食品包装上粘贴的“安全许可”标识一样安心:读者不必担心书的翻译质量,而只需要尽情地享受阅读带来的快乐。当然,要达成这个目标并不容易,但我会在接下来的工作中继续努力,希望大家可以一如既往地支持我。

最后,我要感谢人民邮电出版社和杨海玲编辑又一次把一本有趣的Go语言的书交给我翻译,我也要感谢我的家人和朋友,他们的关怀和帮助让我顺利完成本书的翻译。

黄健宏

2019年10月于清远


一切都在变化,没有东西是亘古不变的。

——赫拉克利特(Heraclitus)

2005年在欧洲旅行期间,Nathan听说了一些关于新Web框架Ruby On Rails的传闻。于是他在赶回加拿大艾伯塔省庆祝圣诞节期间,在市中心的计算机书店购入了一本Agile Web Development with Rails(Pragmatic Bookshelf,2005),并在接下来的两年里将自己的事业从ColdFusion转向了Ruby。

在英国的约克大学,Roger被引荐给了经过彻底精简之后的贝尔实验室,并在那里跟包括Go语言的创造者Rob Pike、Ken Thompson在内的成员一起研究UNIX以及由同一批人发明的Plan 9操作系统。Roger对此产生了极大的兴趣,并在之后开始进行Inferno系统的相关工作,该系统使用了自有的Limbo语言,它是与Go关系密切的一个原型。

当Go在2009年11月作为开源项目对外发布的时候,Roger立即发现了它的潜力,他开始使用Go并为Go的标准库和生态系统做贡献。Roger至今仍然对Go的成功感到高兴,除全职使用Go进行编程之外,他还运营着一个本地的Go聚会。

Nathan虽然观看了Rob Pike发布Go的技术演讲,但他在2011年之前都没有认真地审视过这门语言。直到一位同事高度评价了Go之后,Nathan才在圣诞节假期通读了The Go Programming Language Phrasebook(Addison-Wesley Professional,2012)的毛边版本。在之后的数年里,Nathan从使用Go编写业余项目并撰写Go相关的博客开始,逐渐转向组织本地的Go聚会并在工作中使用Go。

因为工具和技术都在持续地变化和改进,所以对计算机科学的学习总是永无止境的。无论你已经拥有计算机科学学位还是刚开始接触这一行,自学新技能都是非常重要的。我们衷心希望本书可以在你学习Go编程语言的过程中予以帮助。


能够为您撰写本书并帮助您学习Go是一种莫大的荣幸,非常感谢您的阅读!

除封面上的两位作者之外,本书还包含了许多人的贡献。

首先也是最重要的,我们要感谢本书的编辑Jennifer Stout和Marina Michaels提供有价值的反馈信息,并且持续地、循序渐进地推动我们向目标进发。我们要感谢Joel Kotarski和Matt Merkes提供准确的技术编辑,感谢Christopher Haupt提供技术校对,并感谢文字编辑Corbin Collins改善了我们写作的语法和风格。此外,我们还要感谢Bert Bates和系列编辑Dan Maharry、Elesha Hyde,他们的对话和指导对本书的形成提供了帮助。

Olga Shalakhina和Erick Zelaya为本书提供了精彩绝伦的插图,Monica Kamsvaag为本书设计了封面,April Milne负责为本书美化和修饰图表,而Renée French则为Go创造了人见人爱的吉祥物,我们要对他们表示感谢。特别鸣谢Dan Allen,他创建了本书创作时使用的工具AsciiDoctor,并为我们提供了持续的支持。

感谢Marjan Bace、Matko Hrvatin、Mehmed Pasic、Rebecca Rinehart、Nicole Butterfield、Candace Gillhoolley、Ana Romac、Janet Vail、David Novak、Dottie Marsico、Melody Dolab、Elizabeth Martin以及Manning出版社为本书付出的其他工作人员,是他们让本书变成了现实,使你能够亲手读到这本书。

感谢Aleksandar Dragosavljević将本书送达至一众审稿人,感谢包括Brendan Ward、Charles Kevin、Doug Sparling、Esther Tsai、Gianluigi Spagnuolo、Jeff Smith、John Guthrie、Luca Campobasso、Luis Gutierrez、Mario Carrion、Mikaël Dautrey、Nat Luengnaruemitchai、Nathan Farr、Nicholas Boers、Nicholas Land、Nitin Gode、Orlando Sánchez、Philippe Charrière、Rob Weber、Robin Percy、Steven Parr、Stuart Woodward、Tom Goodheard、Ulises Flynn和William E. Wheeler在内的所有审稿人,他们都提供了有价值的反馈信息。我们还要感谢那些通过论坛提供反馈的早期阅读者。

最后,我们还要对Michael Stephens表示感谢,是他提出了撰写一本书的疯狂想法,也感谢Go社区创造了我们乐于为其写书的语言及生态系统。

理所当然地,我要感谢我的父母,是他们生育并抚养了我。我的父母从我小时候开始就鼓励我钻研计算机编程,并为我提供了相应的书本、课程以及接触计算机的机会。

除出现在封面上的官方评论之外,我还要感谢Matthias Stone为本书的早期草稿提供反馈,还有Terry Youngman帮助我进行头脑风暴以获得更多想法。我要感谢埃德蒙顿Go社区为我加油打气,还有我的雇主Mark Madsen给我提供便利,让我得以将写书工作付诸实践。

我要向我的合著者Roger Peppé致以最诚挚的感谢,他通过撰写第7单元而缩短了原本漫长的写作道路,并为本项目注入了强劲的能量。

我得向我的妻子Carmen致以最诚挚的感谢,创作本书占用了我们本该在山间漫步的时间,而她却对此毫无怨言,并且始终如一地支持着我。

非常感谢Nathan Youngman和Manning出版社对我的信任,是他们让我成为本书的合著者,并且在创作本书的最后阶段仍然对我保持耐心。


Go适合各种技术水平的程序员,这对任何大型项目来说都是至关重要的。作为一种相对较为小型的语言,Go的语法极少,需要掌握的概念也不多,因此它非常适合用作初学者的入门语言。

遗憾的是,很多学习Go语言的资源都假设读者拥有C语言的工作经验,而本书的目的则在于弥补这一缺陷,为脚本使用者、业余爱好者和初学者提供一条学习Go语言的康庄大道。为了让起步的过程变得更容易一些,本书的所有代码清单和练习都可以在Go Playground里面执行,你在阅读本书的时候甚至不需要安装任何东西。

如果你曾经使用过诸如JavaScript、Lua、PHP、Perl、Python或者Ruby这样的脚本语言,那么你已经做好了学习Go的万全准备。如果你曾经使用过Scratch或者Excel的公式,或者编写过HTML,那么你毫无疑问可以像Audrey Lim在她的演讲“A Beginner’s Mind”(初学者之心)中所说的一样,选择Go作为你的第一门“真正”的编程语言。虽然掌握Go语言并不是一件容易的事情,需要相应的耐心和努力,但我们希望本书在这个过程中能够助你一臂之力。

本书将以循序渐进的方式讲解高效使用Go语言所必需的概念,并提供大量练习来磨砺你的技能。这是一本初学者指南,需要从头到尾地进行阅读,并且每一章都建立在前面各章的基础之上。本书虽然没有完整地描述Go的所有语言特性,但是涵盖了其中的绝大部分特性,并且提及面向对象设计和并发等高级主题。

无论你是打算使用Go编写大型的并发Web服务,还是只想用Go编写小型脚本和简单的工具,本书都会帮助你打下坚实的基础。

本书提供了练习的参考答案(读者可在异步社区的网站上下载),但提出你自己的解答毫无疑问可以让编程变得更加有趣!

为了区分代码和普通文本,所有代码都将使用fixed-width这样的等宽字体进行表示,并且很多代码清单都会使用注释以突出重要的概念。

读者可以从出版社的网站下载所有代码清单的源代码,里面还包含了本书所有练习的参考答案。你也可以通过GitHub页面来在线阅览这些源代码。

尽管你可以从GitHub上面直接复制并粘贴代码,但我们还是建议你亲手键入书中的示例代码。通过亲手键入代码并修复其中的录入错误,然后试验这些代码,你将能够从书中获得更多经验。

Manning 出版社运营着一个私有的网络论坛,而购买本书的读者就获得了自由访问该论坛的权利。读者可以在论坛上发表关于本书的评论和技术问题、分享自己的练习答案,或者向论坛上的作者和其他用户求助。

Manning出版社承诺为读者提供一个场所,让每位读者都可以与其他读者以及作者进行有意义的对话。但Manning出版社并不保证作者参与讨论的程度,他们对于论坛的一切贡献都是无偿并且自愿的。建议读者尝试向作者提出一些有挑战性的问题以便引起他们的兴趣。Manning出版社保证这个论坛以及过往讨论的存档将在本书在售期间一直在Manning出版社网站上可得。


内森·扬曼(Nathan Youngman)既是一位自学成才的网络开发者,也是一位终生学习概念的践行者。他是加拿大埃德蒙顿市Go聚会(meetup)的组织者,Canada Learning Code的辅导教师以及狂热的地鼠玩偶摄影爱好者。

罗杰·佩珀(Roger Peppé)是一位Go贡献者,他维护着一系列开源Go项目,运营着英国纽卡斯尔市的Go聚会,并且当前正在负责Go云端基础设施软件的相关工作。


本书由异步社区出品,社区(https://www.epubit.com/)为您提供相关资源和后续服务。

本书提供源代码及习题答案的下载,要获得以上配套资源,请在异步社区本书页面中点击 ,跳转到下载界面,按提示进行操作即可。注意:为保证购书读者的权益,该操作会给出相关提示,要求输入提取码进行验证。

作者和编辑尽最大努力来确保书中内容的准确性,但难免会存在疏漏。欢迎您将发现的问题反馈给我们,帮助我们提升图书的质量。

当您发现错误时,请登录异步社区,按书名搜索,进入本书页面,点击“提交勘误”,输入勘误信息,单击“提交”按钮即可。本书的作者和编辑会对您提交的勘误进行审核,确认并接受后,您将获赠异步社区的100积分。积分可用于在异步社区兑换优惠券、样书或奖品。

我们的联系邮箱是contact@epubit.com.cn。

如果您对本书有任何疑问或建议,请您发邮件给我们,并请在邮件标题中注明本书书名,以便我们更高效地做出反馈。

如果您有兴趣出版图书、录制教学视频,或者参与图书翻译、技术审校等工作,可以发邮件给我们;有意出版图书的作者也可以到异步社区在线提交投稿(直接访问www.epubit.com/selfpublish/submission即可)。

如果您来自学校、培训机构或企业,想批量购买本书或异步社区出版的其他图书,也可以发邮件给我们。

如果您在网上发现有针对异步社区出品图书的各种形式的盗版行为,包括对图书全部或部分内容的非授权传播,请您将怀疑有侵权行为的链接发邮件给我们。您的这一举动是对作者权益的保护,也是我们持续为您提供有价值的内容的动力之源。

“异步社区”是人民邮电出版社旗下IT专业图书社区,致力于出版精品IT技术图书和相关学习产品,为作译者提供优质出版服务。异步社区创办于2015年8月,提供大量精品IT技术图书和电子书,以及高品质技术文章和视频课程。更多详情请访问异步社区官网https://www.epubit.com。

“异步图书”是由异步社区编辑团队策划出版的精品IT专业图书的品牌,依托于人民邮电出版社的计算机图书出版积累和专业编辑团队,相关图书在封面上印有异步图书的LOGO。异步图书的出版领域包括软件开发、大数据、AI、测试、前端、网络技术等。

异步社区

微信服务号


根据传统,学习新编程语言的首要步骤,就是准备好相应的工具和环境,以便运行简单的“Hello World”应用程序。但是通过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是如何减少语言中的歧义的。

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编译器的两个优点是什么?

学习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按钮是用来做什么的?

当我们访问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”
}

尽管这段代码非常简短,但它引入了packageimportfunc这3个非常重要的关键字,这些保留的关键字都有它们各自的特殊目的。

package关键字声明了代码所属的包,在本例中这个包的名字就是main。所有用Go编写的代码都会被组织成各式各样的包,并且每个包都对应一个单独的构想,例如,Go语言本身就提供了一个面向数学、压缩、加密、图像处理等领域的标准库。

package关键字之后,代码使用了import关键字来导入自己将要用到的包。一个包可以包含任意数量的函数。例如,math包提供了诸如SinCosTanSqrt等函数,而此处用到的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包提供了什么功能?

Go对于大括号{}的摆放位置非常挑剔。在代码清单1-1中,左大括号{func关键字位于同一行,而右大括号}则独占一行。这是Go语言唯一允许的大括号放置风格,除此之外的其他大括号放置风格都是不被允许的。

Go之所以如此严格地限制大括号的放置风格,与这门语言刚刚诞生时出现的一些情况有关。在早期,使用Go编写的代码总是无一幸免地带有分号,它们就像迷路的小狗一样跟在每条单独的语句后面,例如:

fmt.Println("Hello, fire hydrant");

到了2009年12月,一群“忍者”gopher决定把分号从语言中驱逐出去。好吧,这么说也不太准确。实际上,Go编译器将为你代劳,自动地插入那些可爱的分号。这种机制运行得非常完美,但它的代价就是要求用户必须遵守上面提到的唯一允许的大括号放置风格

如果用户尝试将左大括号和func关键字放在不同的行里面,那么Go编译器将报告一个语法错误:

func main(  ←--- 函数体缺失
{  ←--- 语法错误:在{之前发现了意料之外的分号或新行
}

出现这个问题并不是编译器有意刁难,而是由于分号被插到了错误的位置,导致编译器犯了点儿小迷糊,最终才不得不求助于你。

提示 在阅读本书的时候,亲力亲为、不厌其烦地键入代码清单中的每段代码是一个不错的主意。这样一来,如果你键入了错误的代码,就会看到相应的语法错误,但这并不是一件坏事。能够识别、理解并纠正代码中的错误是一项至关重要的技能,而且坚持不懈也是一种宝贵的品质。

速查1-4

用户必须将左大括号{置于何处才能避免引起语法错误?

为了检验你是否已经掌握了上述知识,请按照接下来展示的练习的要求修改Go Playground中的代码,并点击Run按钮来查看结果。如果你在做练习的过程中遇到麻烦无法继续下去,那么可以通过刷新浏览器来让代码回到最初的状态。

实验:playground.go

你可以通过点击Go Playground中的Share按钮来获得访问当前代码的链接,然后将该链接发布至本书的论坛与其他读者进行分享。

最后,你可以将你的解法和“习题答案”中给出的参考答案进行对比,从而判断其是否正确。


速查1-1答案 Go编译器可以在极短的时间内完成对大型程序的编译,并且它可以在程序运行之前找出代码中的一些人为失误,如拼写错误等。

速查1-2答案 Run按钮可以在谷歌的服务器上编译并执行用户输入的代码。

速查1-3答案

1.Go程序从main包的main函数开始执行。

2.fmt包提供了用于格式化输入和输出的函数。

速查1-4答案 左大括号必须与func关键字位于同一行而不是独占一行,这是Go语言唯一允许的大括号放置风格。



跟母亲菜谱上记载的烹饪方法一样,绝大多数计算机程序都由一系列步骤组成。程序员需要精确地告诉计算机如何完成任务,然后由计算机负责执行程序员的指令。这种通过编写指令来进行编程的方式被称为命令式编程,它就像是在教计算机如何做菜一样!

在本单元中,我们将会了解Go的一些基本知识,并开始学习如何通过Go的句法向计算机发出指令。本单元中的各章将陆续介绍一些知识,这些知识将帮助我们应对本单元最后提出的挑战:构建一个计算去火星旅行所需费用的应用程序。


本章学习目标

计算机程序能够完成许多任务。在本章中,你将编写程序去解决数学问题。

请考虑这一点

我们为什么要编写程序来做那些只需要按一下计算器就能完成的事情呢?

首先,人类的记性通常都不太好,可能无法凭借自身的记忆力精确地记下光速或者火星沿着轨道绕太阳一周所需的时间,而程序和计算机没有这个问题。其次,代码可以保存起来以供之后阅读,它既是一个计算器也是一份参考说明。最后,程序是可执行文件,人们可以随时根据自己的需要来共享和修改它。

人们总是希望自己能够变得更年轻和更苗条,如果你也有同样的想法,那么火星应该能满足你的愿望。火星上的一年相当于地球上的687天,而较弱的重力作用则使得同一物体在火星上的重量约占地球上重量的38%。

为了计算本书作者Nathan在火星上的年龄和体重,我们写下代码清单2-1所示的小程序。Go跟其他编程语言一样,提供了+-*/%等算术操作符,将它们分别用于执行加法、减法、乘法、除法和取模运算。

提示 取模运算符%能够计算出两个整数相除所得的余数。例如,42 % 10的结果为2

代码清单2-1 你好,火星:mars.go

// 我的减重程序  ←--- 为人类读者提供的注释
package main
import "fmt"
// main是所有程序的起始函数  ←--- 为人类读者提供的注释
func main() {
    fmt.Print("My weight on the surface of Mars is ")
    fmt.Print(149.0 * 0.3783)  ←--- 打印56.3667
    fmt.Print(" lbs, and I would be ")
    fmt.Print(41 * 365 / 687)  ←--- 打印21
    fmt.Print(" years old.")
}

注意 虽然代码清单2-1会以磅为单位显示体重,但计量单位的选择对于体重的计算并无影响。无论你使用的是什么计量单位,在火星上的重量都只相当于在地球上重量的37.83%。

这段代码的第一行为注释。当Go在代码里面发现双斜杠//的时候,它会忽略双斜杠之后直到行尾为止的所有内容。计算机编程的本质就是传递信息,好的代码不仅能够把程序员的指令传递给计算机,还能够把程序员的意图传递给其他阅读代码的人。注释的存在正是为了帮助人们理解代码的意图,它不会对程序的行为产生任何影响。

代码清单2-1会调用Print函数好几次,以便将完整的句子显示在同一行里面。达到这一目的的另一种方法是调用Println函数,并向它传递一组由逗号分隔的参数,这些参数可以是文本、数值或者数学表达式

fmt.Println("My weight on the surface of Mars is", 149.0*0.3783, "lbs, and I would be", 41*365.2425/687, "years old.")  ←--- 打印出“My weight on the surface of Mars is 56.3667 lbs, and I would be 21.79758733624454 years old.”

速查2-1

请在Go Playground网站中输入并运行代码清单2-1,然后将作者Nathan的年龄(41)以及体重(149.0)替换成你的年龄和重量,看看自己在火星上的年龄和体重是多少?

提示 在修改代码之后,点击Go Playground中的Format(格式化)按钮。这样Go Playground就会在不改变代码行为的前提下,自动重新格式化代码的缩进和空白。

使用代码清单2-2中展示的Printf函数,用户可以在文本中的任何位置插入给定的值。Printf函数与Println函数同属一族,但前者对输出拥有更大的控制权。

代码清单2-2 Printf:fmt.go

fmt.Printf("My weight on the surface of Mars is %v lbs,", 149.0*0.3783)  ←--- 打印出“My weight on the surface of Mars is 56.3667 lbs,”
fmt.Printf(" and I would be %v years old.\n", 41*365/687)  ←--- 打印出“and I would be 21 years old.”

PrintPrintln不一样的是,Printf接受的第一个参数总是文本,第二个参数则是表达式,而文本中包含的格式化变量%v则会在之后被替换成表达式的

注意 之后的各章将按需介绍更多除 %v之外的其他格式化变量,你也可以通过Go的在线文档查看完整的格式化变量参考列表。

虽然Println会自动将输出的内容推进至下一行,但是PrintfPrint却不会那么做。对于后面这两个函数,用户可以通过在文本里面放置换行符\n来将输出内容推进至下一行。

如果用户指定了多个格式化变量,那么Printf函数将按顺序把它们替换成相应的值:

fmt.Printf("My weight on the surface of %v is %v lbs.\n", "Earth", 149.0)  ←--- 打印出“My weight on the surface of Earth is 149 lbs.”

Printf除可以在句子的任意位置将格式化变量替换成指定的值之外,还能够调整文本的对齐位置。例如,用户可以通过指定带有宽度的格式化变量%4v,将文本的宽度填充至4个字符。当宽度为正数时,空格将被填充至文本左边,而当宽度为负数时,空格将被填充至文本右边:

fmt.Printf("%-15v $%4v\n", "SpaceX", 94)
fmt.Printf("%-15v $%4v\n", "Virgin Galactic", 100)

执行上面这两行代码将打印出以下内容:

SpaceX          $  94
Virgin Galactic $ 100

速查2-2

1.如何才能打印出一个新行?

2.Printf函数在遇到格式化变量%v的时候会产生何种行为?

代码清单2-1中的计数器在计算时使用了类似0.3783这样的字面数值,但并没有具体说明这些数值所代表的含义,程序员有时候会把这种没有说明具体含义的字面数字称为魔数。通过使用常量和变量并为字面数值赋予描述性的名称,我们可以有效地减少魔数的存在。

在了解过居住在火星对于年龄和体重有何种好处之后,我们接下来要考虑的就是旅行所需消耗的时长。对我们的旅程来说,以光速旅行是最为理想的。因为光在太空的真空环境中会以固定速度传播,所以相应的计算将会变得较为简单。与此相反的是,根据行星在绕太阳运行的轨道上所处的位置不同,地球和火星之间的距离将会产生相当大的变化

代码清单2-3引入了两个新的关键字constvar,它们分别用于声明常量和变量。

代码清单2-3 实现光速旅行:lightspeed.go

// 到达火星需要多长时间?
package main
import "fmt"
func main() {
    const lightSpeed = 299792 // km/s
    var distance = 56000000 // km
    fmt.Println(distance/lightSpeed, "seconds")  ←--- 打印出“186 seconds”
    distance = 401000000
    fmt.Println(distance/lightSpeed, "seconds")  ←--- 打印出“1337 seconds”
 }

只要将代码清单2-3中的代码录入Go Playground,然后点击Run按钮,我们就可以计算出从地球出发到火星所需的时间了。能够以光速行进是一件非常便捷的事情,不消一会儿工夫你就能到达目的地,你甚至不会听到有人抱怨“我们怎么还没到?”。

这段代码的第一次计算通过声明distance变量并为其赋予初始值56 000 000 km来模拟火星与地球相邻时的情形,而在进行第二次计算的时候,则通过为distance变量赋予新值401 000 000 km来模拟火星和地球分列太阳两侧时的情形(其中401 000 000 km代表的是火星和地球之间的直线距离)。

注意 lightSpeed常量是不能被修改的,尝试为其赋予新值将导致Go编译器报告错误:“无法对lightSpeed进行赋值”。

注意 变量必须先声明后使用。如果尚未使用var关键字对变量进行声明,那么尝试向它赋值将导致Go报告错误,例如在前面的代码中执行speed = 16就会这样。这一限制有助于发现类似于“想要向distance赋值却键入了distence”这样的问题。

速查2-3

1.尽管SpaceX公司的星际运输系统因为缺少曲速引擎而无法以光速行进,但它仍然能够以每小时100 800 km这一可观的速度驶向火星。如果这个雄心勃勃的公司在2025年1月,也就是地球和火星之间相距96 300 000 km的时候发射宇宙飞船,那么它需要用多少天才能够到达火星?请修改代码清单2-3来计算并回答这一问题。

2.在地球上,一天总共有24小时。如果要在程序中为数字24指定一个描述性的名字,你会用什么关键字?

虽然访问火星也许没有捷径可走,但Go却提供了一些能够让我们少敲些字的快捷方式。

用户在声明变量或者常量的时候,既可以在每一行中单独声明一个变量:

var distance = 56000000
var speed = 100800

也可以一次声明一组变量:

var (
     distance = 56000000
     speed = 100800
)

或者在同一行中声明多个变量:

var distance, speed = 56000000, 100800

需要注意的是,为了保证代码的可读性,我们在一次声明一组变量或者在同一行中声明多个变量之前,应该先考虑这些变量是否相关。

速查2-4

请在只使用一行代码的情况下,同时声明每天包含的小时数以及每小时包含的分钟数。

有几种快捷方式可以让我们在赋值的同时执行一些操作。例如,代码清单2-4中的最后两行就是等效的。

代码清单2-4 赋值操作符:shortcut.go

var weight = 149.0
weight = weight * 0.3783
weight *= 0.3783

Go为加一操作提供了额外的快捷方式,它们的执行方式如代码清单2-5所示。

代码清单2-5 增量操作符

var age = 41
age = age + 1  ←--- 生日快乐!
age += 1
age++

用户可以使用count--执行减一操作,或者使用类似于price /= 2这样简短的方式执行其他常见的算术运算。

注意 顺带一提的是,Go并不支持++count这种见诸C和Java等语言中的前置增量操作。

速查2-5

请用最简短的一行代码实现“从名为weight的变量中减去两磅”这一操作。

让人类随意想出一个介于1至10之间的数字是非常容易的,但如果想要让Go来完成同样的事情,就需要用到rand包来生成伪随机数。这些数字之所以被称为伪随机数,是因为它们并非真正随机,只是看上去或多或少像是随机的而已。

执行代码清单2-6中的代码会显示出两个1 ~ 10的数字。这个程序会先向Intn函数传入数字10返回一个0 ~ 9的伪随机数,然后把这个数字加一并将其结果赋值给变量num。因为常量无法使用函数调用的结果作为值,所以num被声明成了变量而不是常量。

注意 如果我们在写代码的时候忘记对伪随机数执行加一操作,那么程序将返回一个0 ~ 9的数字而不是我们想要的1 ~ 10的数字。这是典型的“差一错误”(off-by-one error)的例子,这种错误是典型的计算机编程错误之一。

代码清单2-6 随机数字:rand.go

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    var num = rand.Intn(10) + 1
    fmt.Println(num)
    num = rand.Intn(10) + 1
    fmt.Println(num)
}

虽然rand包的导入路径math/rand,但是我们在调用Intn函数的时候只需要使用包名rand作为前缀即可,不需要使用整个导入路径。

提示 从原则上讲,我们在使用某个包之前必须先通过import关键字导入该包,但是贴心的Go Playground也可以在需要的时候自动为我们添加所需的导入路径。为此,你需要确保Go Playground中的Imports复选框已经处于选中状态,并点击Format按钮。这样一来,Go Playground就会找出程序正在使用的包,然后更新代码以添加相应的导入路径。

注意 因为Go Playground会把每个程序的执行结果都缓存起来,所以即使我们重复执行代码清单2-6所示的程序,最终也只会得到相同的结果,不过能够做到这一点已经足以验证我们的想法了。

速查2-6

地球和火星相邻时的距离和它们分列太阳两侧时的距离是完全不同的。请编写一个程序,它能够随机地生成一个介于56 000 000 km至401 000 000 km之间的距离。

为了检验你是否已经掌握了上述知识,请尝试完成以下实验。

实验:malacandra.go

Malacandra并不遥远,我们大约只需要28天就可以到达那里。

—— C. S. Lewis,《沉寂的星球》(Out of the Silent Planet)

Malacandra是C. S. Lewis在《太空三部曲》中为火星起的别名。请编写一个程序,计算在距离为56 000 000 km的情况下,宇宙飞船需要以每小时多少千米的速度飞行才能够用28天到达Malacandra。

请将你的解答与“习题答案”中给出的参考答案进行对比。


速查2-1答案 这个问题没有标准答案,程序的具体输出取决于你输入的体重和年龄。

速查2-2答案

1.你可以通过在待打印文本的任意位置添加换行符\n来插入新行,或者直接调用fmt.Println()

2.格式化变量%v将被替换成用户在后续参数中指定的值。

速查2-3答案

1.虽然宇宙飞船在实际中不可能只沿着直线行进,但作为一个粗略的估计,它从地球飞行至火星大约需要用39天。以下是进行计算所需修改的代码:

const hoursPerDay = 24
var speed = 100800    // km/h
var distance = 96300000 // km
fmt.Println(distance/speed/hoursPerDay, "days")

2.因为在地球上一天经过的小时数不会在程序运行的过程中发生变化,所以我们可以使用const关键字来定义它。

速查2-4答案

const hoursPerDay, minutesPerHour = 24, 60

速查2-5答案

weight -= 2

速查2-6答案

// 随机地产生一个从地球到火星的距离(以km为单位)
var distance = rand.Intn(345000001) + 56000000
fmt.Println(distance)



相关图书

Rust游戏开发实战
Rust游戏开发实战
仓颉编程快速上手
仓颉编程快速上手
深入浅出Go语言编程从原理解析到实战进阶
深入浅出Go语言编程从原理解析到实战进阶
Go语言编程指南
Go语言编程指南
JUnit实战(第3版)
JUnit实战(第3版)
Scala速学版(第3版)
Scala速学版(第3版)

相关文章

相关课程