从本节的标题不难看出,我们今天要学这三个方面的知识:Go 的源码结构、添加注释和命令行工具。
其中,实际开发时最常用的就是添加注释了;作为Go语言的基础知识,了解源码的结构是必需的;Go SDK 中提供了多个命令行工具,有助于我们进行编译、安装、获取软件包、测试和性能分析等操作。
万丈高楼平地起,而地基则是高楼的根基。本小节的内容依然属于 Go 语言编程的基础部分,需要大家掌握。
# Go程序源码结构
我们继续探索 Hello World 程序的奥秘,先来回顾完整的代码:
go
复制代码package main
import "fmt"
func main(){
fmt.Println("Hello World!")
}
接下来,我们逐行解释代码。
💡 提示: 作为Go语言基础部分,本小节的内容仅对每行代码做功能性解释,不做深入探讨,我们将在后续的章节中详细阐述。例如,对于“main包”,我们暂时只需要对“包”和“main包”有个印象就可以了。
- 第一行内容为 “package main”,它表示这个源码文件属于 main 包。main 包是每个 Go 应用程序都包含的包,有且只有一个。
- 第二行内容是 “import “fmt"”,它的作用是导入名为 “fmt” 的包,目的在于稍后使用 fmt 包提供的各种能力。一旦某个包被导入,它必须被使用。
- 从第三行开始到最后,是 main() 函数,这个函数比较特殊,它是 Go 程序的“入口”函数,是程序运行的起点。这个函数必须存在且只能存在一个,且必须声明在 main 包中。任何一个 Go 函数都要求使用成对的大括号将函数体包裹起来。
- 第四行调用了 fmt 包中的 Println() 函数,这个函数的作用是将特定的内容输出到控制台上。
- 第五行是 main() 函数的结束。
# 为 Go 源码添加注释
无论使用何种编程语言,为代码添加注释都是必要的。注释的作用是对代码进行解释和说明,目的在于让人们更方便地了解代码。
对于大多数项目,都需要持续一段时间来完成开发和测试,最终上线,上线后还要应对产品的迭代更新。然而,毫不夸张地说,即使仅相隔一周,我们便很可能读不懂代码了,即使这些代码是自己亲手写的。此时,注释就能很好地帮助我们理解这些代码了。
在 Go 语言中,注释分为两类:单行注释和多行注释。
# 单行注释
单行注释也称为行注释,格式为以双斜杠(“//”)开头的一行,可以添加在代码的任何位置。
请大家阅读下面的代码:
go
复制代码package main
import "fmt"
func main(){
//输出"Hello World!"文字
fmt.Println("Hello World!")
}
在这段代码中,添加了一行注释,用于解释下方一行代码的作用。
需要注意的是,在使用注释时,不要连同代码一起注释,被注释的代码不会被执行。但在修改代码时,利用这个特性暂时注释掉将被修改的代码,而非直接删除,可以方便在必要时还原它们。
若要添加空白行,可按照如下格式进行:
go
复制代码//第一行
//
//第三行
//第四行
# 多行注释
多行注释也称为块注释,格式为以 “/” 开头,以 “/” 结束的一行或多行。
请大家阅读下面的代码:
go
复制代码/*
main()函数是Go程序的入口函数
是程序运行的起点
此处输出"Hello World!"
用于验证开发环境配置
*/
func main(){
//输出"Hello World!"文字
fmt.Println("Hello World!")
}
本例在 main() 函数上方添加了多行注释,用于解释 main() 函数的作用。
和单行注释不同,多行注释不允许嵌套使用,如:
go
复制代码/*
main()函数是Go程序的入口函数
/*是程序运行的起点
此处输出"Hello World!"
*/
用于验证开发环境配置
*/
这将导致编译时错误,无法完成编译。
若要添加空白行,可按照如下格式进行:
go
复制代码/*
第一行
第三行
第四行
*/
《代码大全》一书中有提到:“代码是写给人看的”。养成良好的编码习惯不仅对编码本身有利,对开发团队中的队友也是很好的支持。在实际开发中,人员之间的沟通成本可能会庞大到可怕,请大家谨记。
# Go SDK 命令行工具
Go SDK 提供了丰富且实用的命令行工具,涵盖编译、代码格式化、源码获取、测试和性能分析(这部分内容在单独的章节中阐述)等方方面面,本节将为大家介绍常用的工具。
💡 提示:在后面的章节中,我们会介绍使用集成开发环境(IDE)开发、编译和运行 Go 程序。在 IDE 中可以通过可视化的方式执行 Go SDK 中的命令行工具,但作为基础知识的一环,且在实际开发的某些场景下依然需要通过终端执行这些命令,因此了解并掌握这些命令行工具依然很重要。
# go build
go build 命令的作用是编译 Go 源码,并生成可执行的文件。还记得吗?在上一节中我们已经使用过它了!
从原理上说,Go SDK 自 1.9 版本开始就支持并发编译了,能尽可能地发挥电脑的最大性能完成编译,所以 Go 源码的编译速度是非常快的。在编译过程中,除了我们自己写的代码外,如果使用了第三方的包,这些包会被一同编译。当我们执行 go build 命令后,会搜索当前目录下的 go 源码并完成编译。
go build 命令还允许附加参数,方便开发者对编译参数进行配置,具体如下表所示:
参数名 | 作用 |
---|---|
-v | 编译时显示包名 |
-p x | 指定编译时并发的数量(使用x表示),该值默认为CPU的逻辑核心数 |
-a | 强制进行重新构建 |
-n | 仅输出编译时执行的所有命令 |
-x | 执行编译并输出编译时执行的所有命令 |
-race | 开启竞态检测 |
此外,如果我们希望只编译某个 go 源码文件或包,可在 go build 命令后添加文件或包名。例如,现有 file1.go、file2.go 和file3.go,我们只希望编译 file1.go,便可如下执行:
bash
复制代码go build file1.go
# go clean
go clean 命令可以清理当前目录内的所有编译生成的文件,具体包括:
- 当前目录下生成的与包名或者 Go 源码文件同名的可执行文件,以及当前目录中 _obj 和 _test 目录中名为 _testmain.go、test.out、build.out、a.out 以及后缀为 .5、.6、.8、.a、.o和 .so 的文件,这些文件通常是执行go build命令后生成的;
- 当前目录下生成的包名加 “.test” 后缀为名的文件,这些文件通常是执行 go test 命令后生成的;
- 工作区中 pkg 和 bin 目录的相应归档文件和可执行文件,这些文件通常是执行 go install 命令后生成的。
go clean 命令还允许附加参数,具体参数和作用如下表所示:
参数名 | 作用 |
---|---|
-i | 清除关联的安装的包和可运行文件,这些文件通常是执行go install命令后生成的 |
-n | 仅输出清理时执行的所有命令 |
-r | 递归清除在 import 中引入的包 |
-x | 执行清理并输出清理时执行的所有命令 |
-cache | 清理缓存,这些缓存文件通常是执行go build命令后生成的 |
-testcache | 清理测试结果 |
在团队式开发中,通常在每次提交代码前执行 go clean 命令,防止提交编译时生成的文件。
# go run
go run 命令的作用是直接运行 go 源码,不在当前目录下生成任何可执行的文件。
从原理上讲,go run 只是将编译后生成的可执行文件放到临时目录中执行,工作目录仍然为当前目录。同时,go run 命令允许添加参数,这些参数将作为 go 程序的可接受参数使用。
由此可见,go run 命令同样会执行编译操作。但要注意的是,go run 不适用于包的执行。
# gofmt
gofmt 命令的作用是将代码按照Go语言官方提供的代码风格进行格式化操作。
请大家注意,gofmt和go fmt是两个不同的命令。go fmt 命令是 gofmt 的封装,go fmt 支持两个参数:-n 和 -x,分别表示仅输出格式化时执行的命令,以及执行格式化并输出格式化时执行的命令。
执行 gofmt 命令时,可指定文件或目录,也可不指定。当不指定时,gofmt 命令会搜索当前目录中的 go 源码文件,并执行相应的格式化操作。
gofmt 命令还允许附加参数,具体参数和作用如下表所示:
参数名 | 作用 |
---|---|
-l | 仅输出需要进行代码格式化的源码文件的绝对路径 |
-w | 进行代码格式化,并用改写后的源码覆盖原有源码 |
-r rule | 添加自定义的代码格式化规则(使用rule表示),格式为:pattern -> replacement |
-s | 开启源码简化 |
-d | 对比输出代码格式化前后的不同,依赖diff命令 |
-e | 输出所有的语法错误,默认只会打印每行第1个错误,且最多打印10个错误 |
-comments | 是否保留代码注释,默认值为true |
-tabwidth x | 用于指定代码缩进的空格数量(使用x表示),默认值为8,该参数仅在-tabs参数为false时生效 |
-tabs | 用于指定代码缩进是否使用tab(“\t”),默认值为true |
-cpuprofile filename | 是否开启CPU用量分析,需要给定记录文件(使用filename表示),分析结果将保存在这个文件中 |
💡 提示:使用-s参数进行源码简化的规则请参考:https://pkg.go.dev/cmd/gofmt#hdr-The_simplify_command
# go install
go install 命令的作用和 go build 类似,都是将源码编译为可执行的文件,附加参数也基本通用,这里就不再赘述了。区别在于:
- go install 命令在编译源码后,会将可执行文件或库文件安装到约定的目录下;
- go install 命令生成的可执行文件使用包名来命名;
- 默认情况下,go install 命令会将可执行文件安装到 GOPATH\bin 目录下,依赖的三方包会被安装到 GOPATH\bin 目录下。
# go get
go get 命令的作用是获取源码包,这一操作包含两个步骤,分别是下载源码和执行 go install 命令进行安装。使用时,仅需将源码仓库地址追加到 go get 后即可(访问pkg.go.dev/ (opens new window),搜索包名,在包详情页可以找到仓库地址),例如:
bash
复制代码go get github.com/ethereum/go-ethereum
go get 命令还允许附加参数,具体参数和作用如下表所示:
参数名 | 作用 |
---|---|
-d | 仅下载源码包,不安装 |
-f | 在执行-u参数操作时,不验证导入的每个包的获取状态 |
-fix | 在下载源码包后先执行fix操作 |
-t | 获取运行测试所需要的包 |
-u | 更新源码包到最新版本 |
-u=patch | 只小版本地更新源码包,如从1.1.0到1.1.16 |
-v | 执行获取并显示实时日志 |
-insecure | 允许通过未加密的HTTP方式获取 |
若要指定所获取源码包的版本,可以通过添加 “@版本号” 的方式执行。如:
bash
复制代码go get github.com/ethereum/go-ethereum@v1.10.1
在使用 Go SDK 1.17 版本时,有一点需要额外注意:执行 go get 命令可能会收到警告,大意是 go get 命令是不建议使用的。此时,使用go install替换 go get 即可,原因是在未来的 Go SDK 版本中 go get 的作用等同于 go get -d。
如果你对 “go get” 命令感兴趣,可以阅读官方对它的说明,写的非常详细:docs.studygolang.com/doc/go-get-… (opens new window)
# 小结
🎉 恭喜,您完成了本次课程的学习!
📌 以下是本次课程的重点内容总结,需要牢牢把握:
- 了解 Hello World 每行源码的含义,了解 Go 程序源码的结构;
- 掌握为源码添加注释的两种方法;
- 熟练使用 Go SDK 提供的命令行工具(6 个 Go SDK 命令),包括每个命令的参数。
➡️ 在下次课程中,我们会阐述如下内容:
- Go 语言集成开发环境介绍(使用 GoLand );
- 如何使用 GoLand 创建、编译和运行 Go 程序;
- 如何使用 GoLand 进行 Go 代码调试。