Go语言从入门到进阶实战(txt+pdf+epub+mobi电子书下载)


发布时间:2021-04-21 12:06:29

点击下载

作者:徐波

出版社:机械工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Go语言从入门到进阶实战

Go语言从入门到进阶实战试读:

前言

现今,多核CPU已经成为服务器的标配。但是对多核的运算能力挖掘一直由程序员人工设计算法及框架来完成。这个过程需要开发人员具有一定的并发设计及框架设计能力。虽然一些编程语言的框架在不断地提高多核资源使用效率,如Java的Netty等,但仍然需要开发人员花费大量的时间和精力搞懂这些框架的运行原理后才能熟练掌握。

Go语言在多核并发上拥有原生的设计优势。Go语言从2009年11月开源,2012年发布Go 1.0稳定版本以来,已经拥有活跃的社区和全球众多开发者,并且与苹果公司的Swift一样,成为当前非常流行的开发语言之一。很多公司,特别是中国的互联网公司,即将或者已经完成了使用Go语言改造旧系统的过程。经过Go语言重构的系统能使用更少的硬件资源而有更高的并发和I/O吞吐表现。

Go语言简单易学,学习曲线平缓,不需要像C/C++语言动辄需要两到三年的学习期。Go语言被称为“互联网时代的C语言”。互联网的短、频、快特性在Go语言中体现得淋漓尽致。一个熟练的开发者只需要短短的一周时间就可以从学习阶段转到开发阶段,并完成一个高并发的服务器开发。

面对Go语言的普及和学习热潮,本书使用浅显易懂的语言,介绍了GO语言从基础的语法知识到并发和接口等新特性知识,从而带领读者迅速熟悉这门新时代的编程语言。本书特色1.提供同步配套的教学视频

为了让读者更好地学习本书,作者为书中的重点内容录制了配套教学视频,借助这些视频,读者可以更轻松地学习。

作者曾经为慕课网的专业视频制作提供指导,并在慕课网做过多期Go语言、Unity 3D游戏引擎和Cocos游戏引擎等网络教学培训,受到众多开发者的青睐及好评。希望读者能够通过作者录制的视频轻松地学习Go语言。2.来自一线的开发经验及实战例子

本书中的大多数例子及代码都来自于作者多年的口述教学和技术分享会等实践,受到了众多开发者的一致好评。同时,作者本人也是一名开源爱好者,编写了业内著名的cellnet网络库。本书将为读者介绍cellnet的架构和设计思想,以帮助读者剖析cellnet内部的运行机制,从而让读者能方便地使用cellnet快速实现业务逻辑。3.浅显易懂的语言、触类旁通的讲解、循序渐进的知识体系

本书在内容编排上尽量做到通俗易懂;在讲解一些常见编程语言特性时,将Go语言和其他多种语言的特性进行对比,让掌握多种编程语言的开发者能迅速理解Go语言的特性。无论是初学者,还是久经“沙场”的老程序员,都能通过本书快速学习Go语言的精华。4.内容全面,实用性强

本书详细介绍了作者精心挑选的多个实用性很强的例子,如JSON串行化、有限状态机(FSM)、TCP粘包处理、Echo服务器和事件系统等。读者既可以从例子中学习并理解Go语言的知识点,还可以将这些例子应用于实际开发中。本书内容第1章 初识Go语言

本章主要介绍了以下内容:(1)Go语言的特性;(2)使用Go语言的开源项目;(3)安装Go语言开发包和搭建其开发环境。第2章 Go语言基本语法与使用

本章主要介绍了Go语言的基本语法,如变量、各种常见数据类型及常量,此外还介绍了Go 1.9版本中新添加的特性,即类型别名。第3章 容器:存储和组织数据的方式

本章介绍了Go语言编程算法中常用的容器,如数组、切片、映射,以及列表的创建、设置、获取、查询和遍历等操作。第4章 流程控制

本章主要介绍了常见的条件判断、循环和分支语句,包括以下内容:(1)条件判断(if);(2)条件循环(for);(3)键值循环(for range);(4)分支选择(switch);(5)跳转语句(goto);(6)跳出循环(break)和继续循环(continue)。第5章 函数(function)

本章首先介绍了Go语言中较为基础的函数声明格式及命名返回值特性;然后介绍了Go语言中较为灵活的特性,即函数变量和匿名函数;还介绍了一个展示操作与数据分离的示例:字符串的链式处理,从而引出函数闭包概念;之后介绍了Go语言中最具特色的如下几个功能:(1)延迟执行语句(defer)——将语句延迟到函数退出时执行;(2)宕机(panic)——终止程序运行;(3)宕机恢复(recover)——让程序从宕机中恢复。第6章 结构体(struct)

本章介绍了Go语言中最重要的概念:结构体。首先讲解了结构体多种灵活的实例化和成员初始化方法;接着使用面向对象和面向过程等思想,逐步介绍了Go语言中的方法及新的概念接收器;然后使用游戏中经典的位置移动例子,展现了结构体的实际使用方法;最后,使用大量例子介绍了结构体内嵌和类型内嵌内容,并在JSON数据的分离实例中体验Go语言的内嵌结构体的强大功能。

本章中的经典例子:使用事件系统实现事件的响应和处理——展现Go语言的方法与函数的统一调用过程。第7章 接口(interface)

本章介绍了Go语言接口的如下几个知识点:(1)声明接口;(2)实现接口的条件;(3)接口的嵌套组合;(4)接口的转换;(5)接口类型断言和类型分支——判断接口的类型;(6)空接口。

本章中涉及的例子有:便于扩展输出方式的日志系统;使用接口进行数据的排序;使用空接口实现可以保存任意值的字典及实现有限状态机(FSM)等。第8章 包(package)

本章首先介绍了构建工程的基础概念GOPATH,接着介绍了包(package)的创建和导入过程与方法,以及能控制访问权限的导出包内标识符的方法。

本章给出了一个典型的工厂模式自动注册示例,介绍了多个包的定义和使用方法。第9章 并发

本章讲解了Go语言中并发的两个重要概念:轻量级线程(goroutine)和通道(channel)。首先介绍了goroutine的创建方法及一些和并发相关的概念,便于读者理解goroutine和线程的区别与联系;然后介绍了通道的声明、创建和使用方法,使用3个示例,即模拟远程过程调用(RPC)、使用通道响应计时器事件和Telnet回音服务器,来展示通道的实际使用方法;最后介绍了在并发环境下的同步处理方法,如使用互斥锁和等待组等,以及使用竞态检测提前发现并发问题。第10章 反射

本章按照反射的类别分为两部分:反射类型对象(reflect.Type)和反射值对象(reflect.Value)。首先介绍了反射类型的获取及遍历方法,同时介绍了反射类型对象获取结构体标签的方法;接着介绍了反射值对象获取及修改值和遍历值等;最后通过使用反射将结构体串行化为JSON格式字符串的示例,介绍了反射在实际中的运用。第11章 编译与工具

本章介绍了Go语言中常用的编译及工具指令,例如:(1)go build/go install——编译及安装源码;(2)go get——远程获取并安装源码;(3)go test——单元测试和基准测试框架;(4)go pprof——性能分析工具。第12章 “避坑”与技巧

本章首先介绍了作者多年使用Go语言的开发经验和技巧总结,以及一些使用Go语言中可能发生的错误及优化建议,例如合理使用并发、在性能与灵活性中做出取舍后再使用反射等;接着介绍了Go语言中一个不为人知的特性——map的多键索引,利用该特性可以方便地对数据进行多个条件的索引;最后介绍了使用Go语言的Socket处理TCP粘包问题。第13章 实战演练——剖析cellnet网络库设计并实现Socket聊天功能

本章介绍了cellnet网络库的基本特性、流程、架构及如下几个关键概念:(1)连接管理;(2)会话收发数据流程;(3)事件队列;(4)消息编码;(5)消息元信息;(6)接收和发送封包。

本章使用cellnet网络库实现了带有聊天功能的客户端和服务器。本书读者对象

·Go语言初学者;

·Go语言进阶读者;

·编程初学者;

·后端程序初学者;

·前端转后端的开发人员;

·熟悉C/C++、Java和C#语言,想了解和学习Go语言的编程爱好者;

·想用Go语言快速学习编写服务器端程序的开发者;

·相关培训学员;

·各大院校的学生。关于作者

本书由徐波编写,郭聪和张锐参与审核和校对。感谢我的妻子和家人在我写书期间的大力支持。

另外,在本书编写期间,得到了吴宏伟先生的耐心指导,他一丝不苟、细致入微地对书稿进行了审核和校对,这让本书的条理更加清晰,语言更加通俗易懂。在此表示深深的感谢!

虽然我们对书中所述内容都尽量核实,并多次进行了文字校对,但因时间所限,加之水平所限,书中的疏漏和错误在所难免,敬请广大读者批评指正。联系我们请发E-mail到hzbook2017@163.com。徐波 第1章初识Go语言

Go语言是一门新生语言,从其出现就备受大家的喜爱。本章会带领读者领略Go语言的特性,介绍Go语言在国内外公司及项目的应用情况,同时让读者了解这门强大语言背后的三位缔造者及团队成员。为了方便读者跟着本书的步骤进行操作和实践,本章还会介绍如何搭建Go语言的开发环境。1.1 Go语言特性

Go语言是Google公司开发的一种静态型、编译型并自带垃圾回收和并发的编程语言。

Go语言的风格类似于C语言。其语法在C语言的基础上进行了大幅的简化,去掉了不需要的表达式括号,循环也只有for一种表示方法,就可以实现数值、键值等各种遍历。因此,Go语言上手非常容易。

Go语言最有特色的特性莫过于goroutine。Go语言在语言层可以通过goroutine对函数实现并发执行。goroutine类似于线程但是并非线程,goroutine会在Go语言运行时进行自动调度。因此,Go语言非常适合用于高并发网络服务的编写。1.上手容易

很多读者表示自己是在看了介绍后才开始了解这门语言的。他们一般也会使用两到三门编程语言。Go语言对于他们来说,也就是一到两天的熟悉过程,之后就可以开始使用Go语言解决具体问题了。大约一周左右已经可以使用Go语言完成既定的任务了。

Go语言这种从零开始使用到解决问题的速度,在其他语言中是完全不可想象的。学过C++的朋友都知道,一到两年大强度的理论学习和实战操练也只能学到这门语言的皮毛,以及知道一些基本的避免错误的方法。

那么,Go语言到底有多么简单?下面从实现一个HTTP服务器开始了解。

HTTP文件服务器是常见的Web服务之一。开发阶段为了测试,需要自行安装Apache或Nginx服务器,下载安装配置需要大量的时间。使用Go语言实现一个简单的HTTP服务器只需要几行代码,如代码1-1所示。

代码1-1 HTTP文件服务器(具体文件:…/chapter01/httpserver/httpserver.go)01 package main02 03 import (04 "net/http"05 )06 07 func main() {08 09 http.Handle("/", http.FileServer(http.Dir(".")))10 11 http.ListenAndServe(":8080", nil)12 }

代码说明如下:

·第1行,标记当前文件为main包,main包也是Go程序的入口包。

·第3~5行,导入net/http包,这个包的作用是HTTP的基础封装和访问。

·第7行,程序执行的入口函数main()。

·第9行,使用http.FileServer文件服务器将当前目录作为根目录(“/”)的处理器,访问根目录,就会进入当前目录。

·第11行,默认的HTTP服务侦听在本机8080端口。

把这个源码保存为main.go,安装Go语言的开发包,在命令行输入如下命令行:$ go run httpserver.go

在浏览器里输入http://127.0.0.1:8080即可浏览文件,这些文件正是当前目录在HTTP服务器上的映射目录。2.编译输出可执行文件

Go语言的代码可以直接输出为目标平台的原生可执行文件。Go语言不使用虚拟机,只有运行时(runtime)提供垃圾回收和goroutine调度等。

Go语言使用自己的链接器,不依赖任何系统提供的编译器、链接器。因此编译出的可执行文件可以直接运行在几乎所有的操作系统和环境中。

从Go 1.5版本之后,Go语言实现自举,实现了使用Go语言编写Go语言编译器及所有工具链的功能。

使用最经典的Go语言版的“hello world”源码来编译输出一个可执行文件,如代码1-2所示。

代码1-2 Go语言版的hello world!(具体文件:…/chapter01/helloworld/helloworld.go)package mainimport "fmt"func main() { fmt.Println("hello world")}

将这段代码保存为main.go,确认安装Go语言的开发包,使用如下指令可以将这段代码编译为可执行文件:$ go build ./helloworld.go

执行hello world的可执行文件就可以输出“hello world”。

Go语言不仅可以输出可执行文件,还可以编译输出能导入C语言的静态库、动态库。

同时从Go 1.7版本开始,Go语言支持将代码编译为插件。使用插件可以动态加载需要的模块,而不是一次性将所有的代码编译为一个可执行文件。3.工程结构简单

Go语言的源码无须头文件,编译的文件都来自于后缀名为go的源码文件;Go语言无须解决方案、工程文件和Make File。只要将工程文件按照GOPATH的规则进行填充,即可使用go build/go install进行编译,编译安装的二进制可执行文件统一放在bin文件夹下。

后面的章节会介绍GOPATH及go build/go install的详细使用方法。4.编译速度快

Go语言可以利用自己的特性实现并发编译,并发编译的最小元素是包。从Go 1.9版本开始,最小并发编译元素缩小到函数,整体编译速度提高了20%。

另外,Go语言语法简单,具有严谨的工程结构设计、没有头文件、不允许包的交叉依赖等规则,在很大程度上加速了编译的过程。5.高性能

这里以国外的一个编程语言性能测试网站http://benchmarksgame.alioth.debian.org/为测试基准和数据源。这个网站可以对常见的编程语言进行性能比较,网站使用都是最新的语言版本和常见的一些算法。

进行测试的编程语言包括:C(gcc)、C++、Java、JavaScript和Go语言。性能比较如表1-1所示,表中数据的单位为秒,数值越小表明运行性能越好。表1-1 常见编程语言的运行性能比较

可以看出,Go语言在性能上更接近于Java语言,虽然在某些测试用例上不如经过多年优化的Java语言,但毕竟Java语言已经经历了多年的积累和优化。Go语言在未来的版本中会通过不断的版本优化提高单核运行性能。6.原生支持并发

Go语言的特性就是从语言层原生支持并发,无须第三方库、开发者的编程技巧及开发经验就可以轻松地在Go语言运行时来帮助开发者决定怎么使用CPU资源。

Go语言的并发是基于goroutine,goroutine类似于线程,但并非线程。可以将goroutine理解为一种虚拟线程。Go语言运行时会参与调度goroutine,并将goroutine合理地分配到每个CPU中,最大限度地使用CPU性能。

多个goroutine中,Go语言使用通道(channel)进行通信,程序可以将需要并发的程序设计为生产者和消费者的模式,将数据放入通道。通道的另外一端的代码将这些数据进行并发计算并返回结果,如图1-1所示。图1-1 常见编程语言的运行性能

下面代码中的生产者每秒生成一个字符串,并通过通道传给消费者,生产者使用两个goroutine并发运行,消费者在main()函数的goroutine中进行处理,如代码1-3所示。

代码1-3 生产者、消费者并发处理(具体文件:…/chapter01/concurrency/concurrency.go)01 package main02 03 import (04 "fmt"05 "math/rand"06 "time"07 )08 09 // 数据生产者10 func producer(header string, channel chan<- string) {11 12 // 无限循环,不停地生产数据13 for {14 // 将随机数和字符串格式化为字符串发送给通道15 channel <- fmt.Sprintf("%s: %v", header, rand.Int31())16 17 // 等待1秒18 time.Sleep(time.Second)19 }20 }21 22 // 数据消费者23 func customer(channel <-chan string) {24 25 // 不停地获取数据26 for {27 // 从通道中取出数据,此处会阻塞直到信道中返回数据28 message := <-channel29 30 // 打印数据31 fmt.Println(message)32 }33 }34 35 func main() {36 // 创建一个字符串类型的通道37 channel := make(chan string)38 // 创建producer()函数的并发goroutine39 go producer("cat", channel)40 go producer("dog", channel)41 // 数据消费函数42 customer(channel)43 }

代码输出如下:dog: 2019727887cat: 1298498081dog: 939984059cat: 1427131847cat: 911902081dog: 1474941318dog: 140954425cat: 336122540cat: 208240456dog: 646203300

代码说明如下:

·第3行,导入格式化(fmt)、随机数(math/rand)、时间(time)包参与编译。

·第10行,生产数据的函数,传入一个标记类型的字符串及一个只能写入的通道。

·第13行,for{}构成一个无限循环。

·第15行,使用rand.Int31()生成一个随机数,使用fmt.Sprintf()函数将header和随机数格式化为字符串。

·第18行,使用time.Sleep()函数暂停1秒再执行这个函数。如果在goroutine中执行时,暂停不会影响其他goroutine的执行。

·第23行,消费数据的函数,传入一个只能写入的通道。

·第26行,构造一个不断消费消息的循环。

·第28行,从通道中取出数据。

·第31行,将取出的数据进行打印。

·第35行,程序的入口函数,总是在程序开始时执行。

·第37行,实例化一个字符串类型的通道。

·第39行和第40行,并发执行一个生产者函数,两行分别创建了这个函数搭配不同参数的两个goroutine。

·第42行,执行消费者函数通过通道进行数据消费。

整段代码中,没有线程创建,没有线程池也没有加锁,仅仅通过关键字go实现goroutine,和通道实现数据交换。7.性能分析

安装Go语言开发包后,使用Go语言工具链可以直接进行Go代码的性能分析。Go的性能分析工具将性能数据以二进制文件输出,配合Graphviz即可将性能分析数据以图形化的方式展现出来,如图1-2所示。图1-2 配合Graphviz工具生成的性能分析图

图中每个方框代表一个函数的执行流程,Go语言会通过图连接和数据告知每个执行步骤的耗时,较为耗时的流程执行框会变大。开发人员根据这些直观的图表即可迅速定位问题代码的位置。8.强大的标准库

Go语言的标准库覆盖网络、系统、加密、编码、图形等各个方面,可以直接使用标准库的http包进行HTTP协议的收发处理;网络库基于高性能的操作系统通信模型(Linux的epoll、Windows的IOCP);所有的加密、编码都内建支持,不需要再从第三方开发者处获取。Go语言的编译器也是标准库的一部分,通过词法器扫描源码,使用语法树获得源码逻辑分支等。Go语言的周边工具也是建立在这些标准库上。在标准库上可以完成几乎大部分的需求。

Go语言的标准库以包的方式提供支持,如表1-2是Go语言标准库中常见的包及其功能。表1-2 Go语言标准库常用的包及功能9.代码风格清晰、简单

Go语言写起来类似于C语言,因此熟悉C语言及其派生语言(C++、C#、Objective-C等)的人都会迅速熟悉这门语言。

C语言的有些语法会让代码可读性降低甚至发生歧义。Go语言在C语言的基础上取其精华,弃其糟粕,将C语言中较为容易发生错误的写法进行调整,做出相应的编译提示。(1)去掉循环冗余括号

Go语言在众多大师的丰富实战经验的基础上诞生,去除了C语言语法中一些冗余、烦琐的部分。下面的代码是C语言的数值循环:// C语言的for数值循环for(int a = 0;a<10;a++){ // 循环代码}

在Go语言中,这样的循环变为:for a := 0;a<10;a++{// 循环代码}

for两边的括号被去掉,int声明被简化为“:=”,直接通过编译器右值推导获得a的变量类型并声明。(2)去掉表达式冗余括号

同样的简化也可以在判断语句中体现出来,以下是C语言的判断语句:if (表达式){ // 表达式成立}

在Go语言中,无须添加表达式括号,代码如下:if 表达式{ // 表达式成立}(3)强制的代码风格

Go语言中,左括号必须紧接着语句不换行。其他样式的括号将被视为代码编译错误。这个特性刚开始会使开发者有一些不习惯,但随着对Go语言的不断熟悉,开发者就会发现风格统一让大家在阅读代码时把注意力集中到了解决问题上,而不是代码风格上。

同时Go语言也提供了一套格式化工具。一些Go语言的开发环境或者编辑器在保存时,都会使用格式化工具进行修改代码的格式化,让代码提交时已经是统一格式的代码。(4)不再纠结于i++和++i

C语言非常经典的考试题为:int a, b;a = i++;b = ++i;

这种题目对于初学者简直摸不着头脑。为什么一个简单的自增表达式需要有两种写法?

在Go语言中,自增操作符不再是一个操作符,而是一个语句。因此,在Go语言中自增只有一种写法:i++

如果写成前置自增“++i”,或者赋值后自增“a=i++”都将导致编译错误。1.2 使用Go语言的项目

Go语言从发布1.0版本以来备受众多开发者关注并得到广泛使用。Go语言的简单、高效、并发特性吸引了众多传统语言开发者的加入,而且人数越来越多。

使用Go语言开发的开源项目非常多。早期的Go语言开源项目只是通过Go语言与传统项目进行C语言库绑定实现,如Qt、Sqlite等。后期的很多项目都使用Go语言进行重新原生实现,这个过程相对于其他语言要简单一些,这也促成了大量使用Go语言原生开发项目的出现。

下面列举的是原生使用Go语言进行开发的部分项目。1.Docker项目

网址为https://github.com/docker/docker。

介绍:Docker是一种操作系统层面的虚拟化技术,可以在操作系统和应用程序之间进行隔离,也可以称之为容器。Docker可以在一台物理服务器上快速运行一个或多个实例。例如,启动一个CentOS操作系统,并在其内部命令行执行指令后结束,整个过程就像自己在操作系统一样高效。2.golang项目

网址为https://github.com/golang/go。

介绍:Go语言的早期源码使用C语言和汇编语言写成。从Go 1.5版本自举后,完全使用Go语言自身进行编写。Go语言的源码对了解Go语言的底层调度有极大的参考意义,建议希望对Go语言有深入了解的读者读一读。3.Kubernetes项目

网址为https://github.com/kubernetes/kubernetes。

介绍:Google公司开发的构建于Docker之上的容器调度服务,用户可以通过Kubernetes集群进行云端容器集群管理。4.etcd项目

网址为https://github.com/coreos/etcd。

介绍:一款分布式、可靠的KV存储系统,可以快速进行云配置。5.beego项目

网址为https://github.com/astaxie/beego。

介绍:beego是一个类似Python的Tornado框架,采用了RESTFul的设计思路,使用Go语言编写的一个极轻量级、高可伸缩性和高性能的Web应用框架。6.martini项目

网址为https://github.com/go-martini/martini。

介绍:一款快速构建模块化的Web应用的Web框架。7.codis项目

网址为https://github.com/CodisLabs/codis。

介绍:国产的优秀分布式Redis解决方案。8.delve项目

网址为https://github.com/derekparker/delve。

介绍:Go语言强大的调试器,被很多集成环境和编辑器整合。1.3 怎样安装Go语言开发包

要学Go语言,首先要学会Go语言开发包的安装和使用。

Go语言的开发包可以在以下站点下载。

·golang中国,网址为https://www.golangtc.com/download;

·Go语言官方网站,网址为https://golang.org/dl/。

如图1-3所示为golang.org官方网站1.9.1版本的下载页面。图1-3 Go开发包的下载页面

其中加粗部分是官方推荐下载的版本,这些版本的描述如表1-3所示。表1-3 Go安装包命名及对应的平台1.3.1 Windows版安装

Go语言的Windows版安装包一般格式为MSI格式,可以直接安装到系统,Go语言的Windows安装包一般命名如下:go1.9.1.windows-amd64.msi

·1.9.1表示Go安装包的版本;

·Windows表示这是一个Windows安装包;

·amd64表示匹配的CPU版本,这里匹配的是64位CPU。

Windows下Go开发包的默认安装路径是C盘的Go目录下,推荐在这个目录下安装Go开发包,使用起来较为方便。Go开发包安装完毕后占用磁盘空间大概是300MB左右。如图1-4所示为选择路径的截图。

Go开发包的安装没有其他选项,接下来是安装程序的文件复制操作,如图1-5所示。图1-4 Windows下Go开发包的安装目录选择图1-5 Windows下Go开发包的安装过程

安装完成后,安装目录下将生成一些目录,如图1-6所示。图1-6 Windows下Go开发包的安装目录及文件

这个目录的结构遵守GOPATH规则,后面的章节会提到这个概念。GOPATH及相关的目录命名是Go语言编译的核心规则。

Go开发包的安装目录的功能及说明如表1-4所示。表1-4 Go开发包的安装目录的说明

开发时,无须关注这些目录。当读者希望深度了解底层原理时,可以通过上面的介绍继续探索。1.3.2 Linux版安装

Linux版的Go语言压缩包格式如下:go1.9.1.linux-amd64.tar.gz

需要将这个包解压到/usr/local/go下,可以用下列命令来完成:tar -C /usr/local -xzf go1.9.1.linux-amd64.tar.gz

请根据下载的Go语言压缩包的版本进行安装。

接下来,需要将/usr/local/go/bin目录添加到PATH环境变量中,可以使用以下命令来完成:export PATH=$PATH:/usr/local/go/bin

使用go env指令,可以查看Go压缩包是否安装成功:$ go envGOARCH="amd64"GOBIN=""GOEXE=""GOHOSTARCH="amd64"GOHOSTOS="linux"GOOS="linux"GOPATH="/root/go"GORACE=""GOROOT="/usr/local/go"GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"GCCGO="gccgo"CC="gcc"GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/ tmp/go-build305492722=/tmp/go-build -gno-record-gcc-switches"CXX="g++"CGO_ENABLED="1"CGO_CFLAGS="-g -O2"CGO_CPPFLAGS=""CGO_CXXFLAGS="-g -O2"CGO_FFLAGS="-g -O2"CGO_LDFLAGS="-g -O2"PKG_CONFIG="pkg-config"1.4 搭建开发环境

安装Go语言的开发包后,可以选择安装集成开发环境(Integrated Development Environment,IDE)或者编辑器来提高开发效率。

集成开发环境中,推荐使用Jetbrains公司开发的GoLand。Jetbrains公司拥有很多的开发环境和工具,如WebStorm(JavaScript开发环境)、ReSharper(Visual Studio的.NET扩展)、CLion(C/C++开发环境)。

微软公司开发的Visual Studio Code是一个高定制化的轻量编辑器,能够根据自己的需要定制Go语言的开发流程。1.4.1 集成开发环境——Jetbrains GoLand

GoLand是Jetbrains公司在IntelliJ平台上开发的Go语言整合工具开发集成环境,提供Go语言的编辑、编译、调试、工程管理、重构等各种功能,无论对于学习者还是企业项目研发者来说,都是首选的开发环境。下载地址为https://www.jetbrains.com/go/。

GoLand使用Java开发,可以在各种平台上运行。下面演示配置GoLand的过程。1.设置GOROOT

GOROOT是Go语言的安装路径,Go Land会自动识别,如果编译错误,可以尝试手动设置GOROOT,步骤如下。

选择菜单File|Settings|Go|GOROOT,如图1-7所示。图1-7 GoLand中设置GOROOT

Settings下的Go分支是Go语言专属的配置选项。2.设置GOPATH

GOPATH是Go语言编译时参考的工作路径,类似于Java中的Workspace的概念,默认选择一个空目录作为GOPATH即可,如图1-8所示。3.运行hello world

单击main左边的绿色小箭头,并单击go run main.go,即可运行程序。GoLand使用Go语言会在运行时自动编译,如图1-9所示。图1-8 GoLand中设置GOPATH图1-9 GoLand中运行hello world1.4.2 方便定义功能的编辑器——Visual Studio Code

Visual Studio Code(简称VS Code)是一款由微软公司开发的,能运行在Mac OS X、Windows和Linux上的跨平台开源代码编辑器。

VS Code使用JSON格式的配置文件进行所有功能和特性的配置。VS Code可以通过扩展程序为编辑器实现编程语言高亮、参数提示、编译、调试、文档生成等各种功能。1.切换语言

中文版的VS Code下载好后的命令语言都是中文,这让很多英文指令搜索变得非常困难。这里推荐将VS Code的语言切换为英文。

选择VS Code的菜单“查看”命令,在打开的面板中输入“配置语言”,弹出如图1-10所示的界面。图1-10 VS Code中打开配置语言面板

输入信息后按Enter键打开local.json文件,如图1-11所示。图1-11 VS Code中修改显示语言

将图1-11中的zh-CN修改为en-US,关闭VS Code后再重新打开,语言修改就生效了。2.安装Go语言扩展

选择菜单View|Extensions命令,打开扩展面板,如图1-12所示。图1-12 在VS Code的Extensions中找到Go语言扩展

在搜索框中输入Go,找到Rich Go language support for Visual Studio Code字样的扩展,单击右边的绿色按钮Install安装Go语言扩展。3.配置GOPATH

选择菜单File|Preferences|Settings命令,打开User Settings配置,如图1-13所示。图1-13 在VS Code中设置GOPATH

图1-13的左边窗口在安装Go扩展后会增加一个Go configuration配置,这里是Go语言的各种默认参数,左边窗口里的配置不能修改,只能在右边窗口的配置中修改。没有被修改的选项默认使用左边的系统默认配置。

在图1-13右边添加一个JSON字段go.gopath,冒号后面添加用户的源码GOPATH路径。注意别忘记在上一行的末尾添加逗号“,”。4.安装调试器

在用户的源码的GOPATH目录中打开命令行,在命令行中输入以下命令下载dlv调试器。set GOPATH=%cd%go get github.com/derekparker/delve/cmd/dlv

编译好的dlv会放在GOPATH的bin目录下。5.添加配置(1)VS Code中运行Go程序需要创建配置。选择菜单View|Debug,或者单击左边的虫子图标,如图1-14所示。(2)随后在图1-14右边的编辑区域会弹出文件,选择Go:Launch file文件后,如图1-15所示。图1-14 在VS Code中添加运行配置图1-15 在VS Code中选择运行配置种类

此时启动配置会被自动添加到Launch.json中,如图1-16所示。(3)准备一段Go语言的hello world源码,按F9键可以在代码上设置断点,按F5键运行代码,如图1-17所示。图1-16 在VS Code中调试Go源码的运行配置图1-17 在VS Code中调试Go源码 第2章Go语言基本语法与使用

变量、数据类型和常量是编程中最常见,也是很好理解的概念。本章将从Go语言的变量开始,逐步介绍各种数据类型及常量。

Go语言在很多特性上和C语言非常相近。如果读者有C语言基础,那么本章的内容阅读起来将会非常轻松;如果读者没有C语言基础也没关系,因为本章内容非常简单易懂。2.1 变量

变量的功能是存储用户的数据。不同的逻辑有不同的对象类型,也就有不同的变量类型。经过半个多世纪的发展,编程语言已经形成一套固定的类型,这些类型在不同的编程语言中基本是相通的。常见变量的数据类型有:整型、浮点型、布尔型、结构体等。

Go语言作为C语言家族的新派代表,在C语言的定义方法和类型上做了优化和调整,更加灵活易学。

Go语言的每一个变量都拥有自己的类型,必须经过声明才能开始用。2.1.1 声明变量

下面先通过一段代码了解变量声明的基本样式。01 var a int02 var b string03 var c []float3204 var d func() bool05 var e struct{06 x int07 }

代码说明如下:

·第1行,声明一个整型类型的变量,可以保存整数数值。

·第2行,声明一个字符串类型的变量。

·第3行,声明一个32位浮点切片类型的变量,浮点切片表示由多个浮点类型组成的数据结构。

·第4行,声明一个返回值为布尔类型的函数变量,这种形式一般用于回调函数,即将函数以变量的形式保存下来,在需要的时候重新调用这个函数。

·第5行,声明一个结构体类型的变量,这个结构体拥有一个整型的x字段。

上面代码的共性是,以var关键字开头,要声明的变量名放在中间,而将其类型放在后面。

变量的声明有几种形式,通过下面几节进行整理归纳。1.标准格式

Go语言的变量声明格式为:var 变量名 变量类型

变量声明以关键字var开头,后置变量类型,行尾无须分号。2.批量格式

觉得每行都用var声明变量比较烦琐?没关系,还有一种为懒人提供的定义变量的方法:var ( a int b string c []float32 d func() bool e struct { x int })

使用关键字var和括号,可以将一组变量定义放在一起。2.1.2 初始化变量

Go语言在声明变量时,自动对变量对应的内存区域进行初始化操作。每个变量会初始化其类型的默认值,例如:

·整型和浮点型变量的默认值为0。

·字符串变量的默认值为空字符串。

·布尔型变量默认为bool。

·切片、函数、指针变量的默认为nil。

当然,依然可以在变量声明时赋予变量一个初始值。回顾:在C语言中,变量在声明时,并不会对变量对应内存区域进行清理操作。此时,变量值可能是完全不可预期的结果。开发者需要习惯在使用C语言进行声明时要初始化操作,稍有不慎,就会造成不可预知的后果。

在网络上只有程序员才能看懂的“烫烫烫”和“屯屯屯”的梗,就来源于C/C++中变量默认不初始化。

微软的VC编译器会将未初始化的栈空间以16进制的0xCC填充,而未初始化的堆空间使用0xCD填充,而0xCCCC和0xCDCD在中文的GB2312编码中刚好对应“烫”和“屯”字。

因此,如果一个字符串没有结束符“\0”,直接输出的内存数据转换为字符串就刚好对应“烫烫烫”和“屯屯屯”。1.标准格式var 变量名 类型 = 表达式

例如:游戏中,玩家的血量初始值为100。可以这样写:var hp int = 100

这句代码中,hp为变量名,类型为int,hp的初始值为100。

上面代码中,100和int同为int类型,int可以认为是冗余信息,因此可以进一步简化初始化的写法。2.编译器推导类型的格式

在标准格式的基础上,将int省略后,编译器会尝试根据等号右边的表达式推导hp变量的类型。var hp = 100

等号右边的部分在编译原理里被称做“右值”。

下面是编译器根据右值推导变量类型完成初始化的例子。01 var attack = 4002 03 var defence = 2004 05 var damageRate float32 = 0.1706 07 var damage = float32(attack-defence) * damageRate08 09 fmt.Println(damage)

代码说明如下:

·第1和3行,右值为整型,attack和defence变量的类型为int。

·第5行,表达式的右值中使用了0.17。Go语言和C语言一样,编译器会尽量提高精确度,以避免计算中的精度损失。

默认情况下,如果不指定damageRate变量的类型,Go语言编译器会将damageRate类型推导为float64。由于这个例子中不需要float64的精度,所以强制指定类型为float32。

·第7行,将attack和defence相减后的数值结果依然为整型,使用float32()将结果转换为float32类型,再与float32类型的damageRate相乘后,damage类型也是float32类型。

·第9行,输出damage的值。提示:damage变量的右值是一个复杂的表达式,整个过程既有attack和defence的运算还有强制类型转换。强制类型转换会在后面的章节中介绍。

代码输出如下:3.43.短变量声明并初始化

var的变量声明还有一种更为精简的写法,例如:hp := 100

这是Go语言的推导声明写法,编译器会自动根据右值类型推断出左值的对应类型。注意:由于使用了“:=”,而不是赋值的“=”,因此推导声明写法的左值变量必须是没有定义过的变量。若定义过,将会发生编译错误。

如果hp已经被声明过,但依然使用“:=”时编译器会报错,代码如下:// 声明hp变量var hp int// 再次声明并赋值hp := 10

编译报错如下:no new variables on left side of :=

提示,在“:=”的左边没有新变量出现,意思就是“:=”的左边变量已经被声明了。

短变量声明的形式在开发中的例子较多,比如:conn, err := net.Dial("tcp","127.0.0.1:8080")

net.Dial提供按指定协议和地址发起网络连接,这个函数有两个返回值,一个是连接对象,一个是err对象。如果是标准格式将会变成:var conn net.Connvar err errorconn, err = net.Dial("tcp", "127.0.0.1:8080")

因此,短变量声明并初始化的格式在开发中使用比较普遍。注意:在多个短变量声明和赋值中,至少有一个新声明的变量出现在左值中,即便其他变量名可能是重复声明的,编译器也不会报错,代码如下:conn, err := net.Dial("tcp", "127.0.0.1:8080")conn2, err := net.Dial("tcp", "127.0.0.1:8080")

上面的代码片段,编译器不会报err重复定义。2.1.3 多个变量同时赋值

编程最简单的算法之一,莫过于变量交换。交换变量的常见算法需要一个中间变量进行变量的临时保存。用传统方法编写变量交换代码如下:var a int = 100var b int = 200var t intt = aa = bb = tfmt.Println(a, b)

在计算机刚发明时,内存非常“精贵”。这种变量交换往往是非常奢侈的。于是计算机“大牛”发明了一些算法来避免使用中间变量:var a int = 100var b int = 200a = a ^ bb = b ^ aa = a ^ bfmt.Println(a, b)

这样的算法很多,但是都有一定的数值范围和类型要求。

到了Go语言时,内存不再是紧缺资源,而且写法可以更简单。使用Go的“多重赋值”特性,可以轻松完成变量交换的任务:var a int = 100var b int = 200b, a = a, bfmt.Println(a, b)

多重赋值时,变量的左值和右值按从左到右的顺序赋值。

多重赋值在Go语言的错误处理和函数返回值中会大量地使用。

例如,使用Go语言进行排序时就需要使用交换,代码如下:01 type IntSlice []int02 03 func (p IntSlice) Len() int { return len(p) }04 func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }05 func (p IntSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }

代码说明如下:

·第1行,将[]int声明为IntSlice类型。

·第3行,为这个类型编写一个Len方法,提供切片的长度。

·第4行,根据提供的i、j元素索引,获取元素后进行比较,返回比较结果。

·第5行,根据提供的i、j元素索引,交换两个元素的值。2.1.4 匿名变量——没有名字的变量

在使用多重赋值时,如果不需要在左值中接收变量,可以使用匿名变量。

匿名变量的表现是一个“_”下画线,使用匿名变量时,只需要在变量声明的地方使用下画线替换即可。

例如:01 func GetData() (int, int) {02 return 100, 20003 }04 05 a, _ := GetData()06 07 _, b := GetData()08 09 fmt.Println(a, b)

代码输出如下:100 200

GetData()是一个函数,拥有两个整型返回值。每次调用将会返回100和200两个数值。

代码说明如下:

·第5行只需要获取第一个返回值,所以将第二个返回值的变量设为下画线。

·第7行将第一个返回值的变量设为匿名。

匿名变量不占用命名空间,不会分配内存。匿名变量与匿名变量之间也不会因为多次声明而无法使用。提示:在Lua等编程语言里,匿名变量也被叫做哑元变量。2.2 数据类型

Go语言中有丰富的数据类型,除了基本的整型、浮点型、布尔型、字符串外,还有切片、结构体、函数、map、通道(channel)等。Go语言的基本类型和其他语言大同小异,切片类型有着指针的便利性,但比指针更为安全,很多高级语言都配有切片进行安全和高效率的内存操作。

结构体是Go语言基础的复杂类型之一,后面会用单独的一章进行讲解。

函数也是Go语言的一种数据类型,可以对函数类型的变量进行赋值和获取,函数特性较多,将被放在独立章节讲解。

map和切片是开发中常见的数据容器类型,会放在第3章进行统一介绍。

通道与并发息息相关,读者会在第9章了解通道的细节。2.2.1 整型

整型分为以下两个大类。

·按长度分为:int8、int16、int32、int64

·还有对应的无符号整型:uint8、uint16、uint32、uint64。

其中,uint8就是我们熟知的byte型,int16对应C语言中的short型,int64对应C语言中的long型。1.自动匹配平台的int和uint

Go语言也有自动匹配特定平台整型长度的类型——int和uint。

可以跨平台的编程语言可以运行在多种平台上。平台的字节长度是有差异的。64位平台现今已经较为普及,但8位、16位、32位的操作系统依旧存在。16位平台上依然可以使用64位的变量,但运行性能和内存性能上较差。同理,在64位平台上大量使用8位、16位等与平台位数不等长的变量时,编译器也是尽量将内存对齐以获得最好的性能。

不能正确匹配平台字节长度的程序就类似于用轿车运一头牛和用一辆卡车运送一头牛的情形一样。

在使用int和uint类型时,不能假定它是32位或64位的整型,而是考虑int和uint可能在不同平台上的差异。2.哪些情况下使用int和uint

逻辑对整型范围没有特殊需求。例如,对象的长度使用内建len()函数返回,这个长度可以根据不同平台的字节长度进行变化。实际使用中,切片或map的元素数量等都可以用int来表示。

反之,在二进制传输、读写文件的结构描述时,为了保持文件的结构不会受到不同编译目标平台字节长度的影响,不要使用int和uint。2.2.2 浮点型

Go语言支持两种浮点型数:float32和float64。这两种浮点型数据格式遵循IEEE 754标准。

·float32的浮点数的最大范围约为3.4e38,可以使用常量定义:math.MaxFloat32。

·float64的浮点数的最大范围约为1.8e308,可以使用一个常量定义:math.MaxFloat64。

打印浮点数时,可以使用fmt包配合动词“%f”,代码如下:01 package main02 03 import (04 "fmt"05 "math"06 )07 08 func main() {09 10 fmt.Printf("%f\n", math.Pi)11 12 fmt.Printf("%.2f\n", math.Pi)13 }

代码说明如下:

·第10行,按默认宽度和精度输出整型。

·第12行,按默认宽度,2位精度输出(小数点后的位数)。

代码输出如下:3.1415933.142.2.3 示例:输出正弦函数(Sin)图像

在Go语言中,正弦函数由math包提供,函数入口为math.Sin。正弦函数的参数为float64,返回值也是float64。在使用正弦函数时,根据实际精度可以进行转换。

Go语言的标准库支持对图片像素进行访问,并且支持输出各种图片格式,如JPEG、PNG、GIF等。1.设置图片背景色

代码2-1 输出正弦图像(具体文件:…/chapter02/sinimage/sinimage.go)01 // 图片大小02 const size = 30003 04 // 根据给定大小创建灰度图05 pic := image.NewGray(image.Rect(0, 0, size, size))06 07 // 遍历每个像素08 for x := 0; x < size; x++ {09 for y := 0; y < size; y++ {10 // 填充为白色11 pic.SetGray(x, y, color.Gray{255})12 }13 }

代码说明如下:

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载