Go语言并发编程系列: 第一章:Go的前世今生
Go语言并发编程系列: 第二章:Go安装部署
Go语言并发编程系列: 第三章:Go语法介绍
Go语言并发编程系列: 第四章:多线程编程概述
Go语言并发编程系列: 第五章:Go的并发原理
Go语言并发编程系列: 第六章:Go锁的应用
Go语言并发编程系列: 第七章:实战-聊天机器人
Go语言并发编程系列: 第八章:实战-Go实现一个软件性能测试工具
Go语言并发编程系列: 第九章:实战-Go实现Concurrent Map
Go语言并发编程系列: 第十章:实战-Go实现网络爬虫
文章目录
一,安装和设置
安装Go非常的简易,进入网站 https://golang.google.cn/dl/,下载对应系统的安装包。
我们以windows10系统为例,进行简要的安装和配置介绍,我们下载:go1.15.3.windows-amd64.msi 安装包,双击安装包,根据提示默认安装就行。
安装结束后打开命令行工具输入go version回车,如果显示G的版本,则表示Go安装成功。
进入Go安装目录,其中包含所有Go语言相关的文件。
- api文件夹。用于存放Go版本升级的增量API文件。包含公开的变量,常量,函数等。这些API增量文件用于G语言API检查。
- bin文件夹。用于存放主要的标准命令文件,包括go、 godot和 gofmt。
- blog文件夹。用于存放官方博客中的所有文章,这些文章都是 Markdown格式的。
- doc文件夹。用于存放标准库的HTML格式的程序文档。我们可以通过godoc命令启动一个Web程序展现这些文档。
- lib文件夹。用于存放一些特殊的库文件。
- misc文件夹。用于存放一些辅助类的说明和工具。
- pkg文件夹。用于存放安装Go标准库后的所有归档文件。
- src文件夹。用于存放Go自身、Go标准工具以及标准库的所有源码文件。
- test文件夹。存放用来测试和验证Go本身的所有相关文件。
我们还需要设置一个环境变量,即:GOROOT。GOROOT的值应该是Go的根目录。这里是C:\Go。另外,环境变量中PATH中也应该增加一项,即$GOROOT/bin。这样就可以在任意目录下使用那几个Go命令了。
至此,GO已经安装好,并且已经对Go的体系结构有一个初步的了解。
二,工作目录结构
推荐使用JetBrains GoLand 这个IDE进行Go应用的开发,下载地址:https://www.jetbrains.com/go/。
Go是一门开放的编程语言,它提供了go get命令从各个第三方开源代码库(例如:GitHub)下载开源代码并使用。Go也是一门严谨的语言,对项目的目录结构有统一的规范和要求,下面我们详细说明Go的工作目录结构。
2.1,工作区
Go的工作区域应该包含3个子文件目录:src目录,pkg目录,bin目录。下面详细说明。
-
src目录。保存我们开发的Go源码文件,并且以代码包的形式组织保存,这里的代码包与src下的子目录一一对应。例如,若一个Go源码文件被声明为属于代码包util,那么它就应当保存在src/util目录下面。如果你不这么做,而是把Go源码文件直接放在src目录下面,这样也是可以的,但这样的话Go源码文件就只能被声明为main代码包。我们强烈建议你不要这样做,这样很容易引起混乱,还是各个不同功能的Go源码文件放在各个不同的功能代码包里。
-
pkg目录。用于存放通过go install命令安装后的代码包的归档文件。前提是代码包中必须包含Go库源码文件。归档文件是指那些名称以 “.a” 结尾的文件。该目录与GOROOT目录下的pkg目录功能类似。区别在于,工作区中的pkg目录专门用来存放用户代码的归档文件。编译和安装用户代码的过程一般会以代码包为单位进行。比如util包被编译安装后,将生成一个名为util.a的归档文件,并存放在当前工作区的pkg目录下的平台相关目录中。
-
bin目录。与pkg目录类似,在通过go install命令完成安装后,保存由Go命令源码文件生成的可执行文件。在Linux系统下,这个可执行文件名称一般与源码文件的主文件名称相同。而在windows系统中,这个可执行文件的名称则是源码文件主文件名称后面加.exe后缀。
下图既是我们用GoLand进行Go程序开发的一个标准目录结构。
2.2,GOPATH环境变量
我们需要将工作区的目录路劲添加到环境变量GOPATH中。否则,即使处于同一工作区,代码之间也无法通过绝对代码包路径调用。在实际开发环境中,工作区可以只有一个,也可以有多个,这些工作区的目录路径都需要添加到GOPATH中。与GOROOT一样,我们应确保GOPATH一直有效。
如果你是用GoLand集成IDE进行GO的开发,也可以直接在IDEA中进行设置。
三,代码包的使用
在Go语言中,代码包是代码编译和安装的基本单元,也是代码有效组织形式。
3.1,包的声明
Go源码文件的第一行必须是以包的声明开始。比如src/util 目录下所有的源文件必须在第一行声明:
package "util"
package是Go中用于包声明的关键字。Go规定包声明中的包名是代码包路径的最后一个元素。比如src/com/standard/log 包的源码文件包声明中的包名是log。
3.2,包的导入
代码包standard/chapter2中run.go需要依赖log子包和util子包,因此需要在源码文件中导入语句如下:
import "standard/chapter2/log"
import "standard/chapter2/util"
import后面即是代码包在工作区src目录下的相对路径。
导入多个代码包时也可以用圆括号包起来,如下:
import (
"standard/chapter2/log"
"standard/chapter2/util"
)
同一个源文件中导入的多个代码包最后一个元素不能重复,一个解决方法是为其中一个起个别名,例如:
import (
"github.com/ukse/logger"
mylogger "standard/chapter2/logger"
)
如果想不加前缀而直接使用某个依赖包中的程序实体,就可以用 " . " 来替代别名,例如:
. import "standard/chapter2/log"
注意到那个 " . "了吗,这样,在当前源文件中,我们就可以这样用了:
var logger = MyLogger ("test");//MyLogger是standard/chapter2/log包中的函数
注意到,MyLogger函数的首字母是大写的,实际上,标识符的首字母的大小写控制着对变量,常量,函数,类型等的访问权限。如果标识符的首字母是大写的,那么它所对应的变量,常量,函数,类型等就可以被本代码包之外的代码访问到,也可以导出和公开的。否则,只能被本包内的代码访问。要想被外部代码访问或导出,还需要额外满足以下两个条件。
- 变量,常量,函数,类型等必须是非局部的。局部是指:它被定义在函数或者结构体的内部。
- 代码包所属目录必须包含在GOPATH中定义的工作区目录内。
代码包导入还有另外一种情况:如果只想初始化某个代码包,而不需要在当前源码文件中使用那个代码包中的任何程序,就可以使用 “ _ ” 来替代别名,如下所示:
import (
_ "standard/chapter2/log"
)
这种情况下,我们只是触发了这个代码包中的初始化操作(如果有的话),符号 “ _ ” 应用很广泛,在后面章节你还可以经常看到它的身影。
3.3,包的初始化
在Go中可以有专门的函数负责代码包的初始化操作,即包初始化函数。这个函数需无任何参数声明和结果返回声明,且名称必须为 init,如下:
func init () {
fmt.Println("Initialize...");
}
init函数会在main函数(代码包的入口函数)执行前执行完毕,并且只会执行一次。
如下示例:
package main
import (
"fmt"
"runtime"
)
func init () {
fmt.Printf("Map : %v\n", m)
msg = fmt.Sprintf("OS: %s, Arch: %s", runtime.GOOS, runtime.GOARCH)
}
var m = map[string]string{"a":"AA", "b":"BB", "c":"CC"}
var msg string
func main() {
fmt.Println(msg)
}
运行上面这个文件,结果:
Map : map[a:AA b:BB c:CC]
OS: windows, Arch: amd64
输出的结果的第一行是m的值赋值后的结果。这验证了:当前代码包中的所有全局变量的初始化会在init初始化函数执行之前完成。
第二行是main函数打印的msg的值,而msg的值在init初始化函数中被初始化。这验证了:初始化函数会在main函数执行之前执行完毕。
同一个代码包中可以有多个初始化函数,Go不会保证同一个代码包中的多个初始化函数的执行顺序。另外,被导入的代码包的初始化函数会优先执行。在上例中,fmt和runtime包中的init函数会先执行,然后才会执行代码包中的初始化函数。
四,Go常用命令介绍
Go为我们提供了大量处理Go程序的命令和工具。go命令就是其中最常用的一个,它有许多子命令,下面一一详述。
- build。用于编译Go源码文件,然后生成可执行文件。
- clean。用于清除Go其他命令执行后遗留下来的临时文件。
- doc。用于生成Go源码中的文档。
- env。打印Go相关的环境信息。
- fix。用于修正代码包中包含的过时语法和调用。通过这个命令我们在升级Go语言版本时,可以快速方便的同步升级我们的源码程序。
- fmt。用于格式化Go源码文件。
- generate。用于识别Go源码文件中的go:generate注释。
- get。用于下载,编译和安装指定的代码包以及依赖包。我们下载一些第三方的API都靠这个命令。
- install。用于编译并安装指定的代码包。install命令执行完后,工作区bin目录会生成相应可执行文件,而安装库源码文件后,工作区pkg目录下 会生成相应归档文件。
- list。用于输出代码包的信息。
- run。用于编译并运行指定源码文件。run命令可不生成可执行文件而直接运行源码文件。
- test。测试执行的源码文件,当然,要存在测试源码文件。
- tool。用于运行Go语言的特殊工具。
- vet。检查指定的源码文件,并报告发现可疑代码问题。可用于找到程序中的潜在错误。
- version。查看Go语言的版本信息。
五,HelloWorld示例
依惯例,下面给出一个helloworld示例程序。
package main
import (
"bufio"
"os"
"fmt"
)
func main() {
inputReader := bufio.NewReader(os.Stdin)
fmt.Println("请输入姓名:")
input, err := inputReader.ReadString('\n');
if err != nil {
fmt.Printf("出现错误: %s\n", err)
} else {
input = input[:len(input) - 1]
fmt.Printf("你好 %s ! \n", input)
}
}
这里导入了两个我们未曾接触过的标准库代码包 bufio 和 os, 另外还对字符串值做了切片。操作符:= 用于在声明局部变量时同时对其赋值。Go允许我们同时对多个值赋值,比如上例中的input 和err 。能够如此赋值的一个原因是Go中的函数可以返回多个结果值。作为结果之一的err用于接收可能发生的错误,这也是Go中大量使用的方式。
程序运行结果:
请输入姓名:
王刚
你好 王刚 !
六,总结
本章讨论了Go的安装设置,工作区目录的介绍,包的介绍,最后给出了一个示例程序,在学习Go的过程中我强烈建议你去下载本教程的示例程序,然后运行,然后自己再修改一下,或者仿造同样的思路编写自己的程序,这也是是学习Go最快速有效的学习方法(其实不关学习哪门编程语言,这都是最快速有效的方法)。关注以下公众号回复 go 获取完整项目源码示例。