- 文档/教程
【免费下载链接】90DaysOfDevOps
This repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.
导读
本文是《90DaysOfDevOps》学习路线中 Go 语言模块的第 9 天(对应 2022/pt-br/Days/day09.md),在 第 8 天 完成 Go 安装并写出第一个main.go之后,这里将把那份只有 6 行的 Hello World 程序逐行拆解,讲清楚"编译"到底做了什么、"包(package)"为什么存在、package main与func main()为什么是强制规则、import "fmt"与fmt.Println()又如何协作。读完本文,你将能够独立解释 Go 程序的启动流程,并具备阅读与扩展 2022/Days/Go/hello.go 这类入门源码的基础能力。
图为第 8 天创建main.go后使用go build main.go将人类可读的源代码编译为机器可执行程序的过程示意。
为什么需要先理解"编译"
在逐行读代码之前,必须先建立对编译的基本认知。Python、Java、Go、C++ 等我们常用的编程语言都属于高级语言(high-level languages):它们以人类可读的文本形式存在。但机器(CPU)真正执行程序时,需要的是机器码(machine code)。因此我们必须把人类可读的源代码"翻译"成机器能理解的形式,这个过程就叫编译(compiling)。
回到 第 8 天 的操作:我们创建了一个简单的main.go,然后执行
go build main.go这条命令就会把源代码编译成可执行的二进制文件。第 8 天还演示了另一种运行方式:
go run main.go两者的区别值得说明:go run会先编译再立即运行,适合开发调试阶段快速验证;go build只产出可执行文件,适合最终分发。第 8 天文档中还展示了构建产物(Windows 下为main.exe)执行后输出Hello #90DaysOfDevOps的过程。
一个非常实用的补充是:Go 支持交叉编译(cross-compilation),即在一次构建中为多个操作系统与 CPU 架构产出二进制。仓库中的 2022/Days/Go/makefile 就给出了一个真实示例:
BINARY_NAME=90DaysOfDevOps build: GOARCH=amd64 GOOS=darwin go build -o ${BINARY_NAME}_0.2_darwin main.go GOARCH=amd64 GOOS=linux go build -o ${BINARY_NAME}_0.2_linux main.go GOARCH=amd64 GOOS=windows go build -o ${BINARY_NAME}_0.2_windows main.go GOARCH=arm64 GOOS=linux go build -o ${BINARY_NAME}_0.2_linux_arm64 main.go GOARCH=arm64 GOOS=darwin go build -o ${BINARY_NAME}_0.2_darwin_arm64 main.go可以看到,通过设置GOOS(目标操作系统)与GOARCH(目标 CPU 架构)两个环境变量,同一份main.go可以同时产出 macOS、Linux、Windows 以及 arm64 架构的可执行文件——这正是"编译"环节在工程实践中的价值体现。
什么是包(Package)
包(package)是 Go 组织源码的基本单位:它是同一个目录下、被编译在一起的一组源文件。更直白地说,包就是同一目录下的一堆.go文件。
沿用第 8 天创建的Hello文件夹:当你进入更复杂的 Go 程序后,可能会发现程序由folder1、folder2、folder3等多个目录构成,每个目录各自包含不同的.go文件,组合起来就是一个由多个包组成的完整程序。
使用包带来的核心收益是代码复用:我们不必从零手写一切。比如程序里需要计算器功能,很可能已经存在包含数学函数的现成 Go 包,直接导入到代码中即可,长期来看能节省大量时间与精力。Go 官方鼓励将代码组织成包,正是为了让源码更容易复用、更容易维护。
打开我们的 Hello World:逐行拆解
下面是 2022/Days/Go/hello.go 的完整内容(仓库中实际保存的版本,输出消息为"Until tomorrow #90DaysOfDevOps",与第 8 天首次创建的"Hello #90DaysOfDevOps"略有不同,属正常迭代):
package main import "fmt" func main() { fmt.Println("Until tomorrow #90DaysOfDevOps") }图为main.go源码文件在编辑器中打开后的整体视图,本文接下来按行逐一讲解。
第 1 行:package main
第一行写着package main,表示这个文件归属于名为main的包。所有.go文件都必须归属某个包,并且第一行必须是package 包名形式的声明。
包的名称可以按你的意愿命名,但这里的main是一个规则约定:因为程序执行的起点就在这个包里,所以包含入口的程序包必须命名为main。这一点可以从仓库中的多个示例得到印证——2022/Days/Go/day11_example1.go、day12_example1.go等后续天数的示例文件,第一行同样都是package main。
第 5 行:func main()——程序的入口
无论何时编译并执行代码,我们都必须告诉机器"执行从哪里开始"。Go 通过一个名为main的函数来完成这件事:机器会在程序包中查找名为main的函数,把它当作程序入口点。
函数(function)是一段能够完成特定任务、并可在整个程序中被调用的代码块。用关键字func可以声明任意名字的函数,但在这个场景下必须命名为main,因为它是代码开始执行的地方。
注意第 2 行是空行,第 4 行的func main() {后面是函数体开始。仓库中的 2022/Days/Go/hello.go 第 5~7 行即为此函数体:
func main() { fmt.Println("Until tomorrow #90DaysOfDevOps") }第 3 行:import "fmt"
第 3 行的import表示你要把另一个包引入到你的主程序中。这里导入的是 Go 官方提供的标准包fmt,该包内包含Println()函数——正是由于这一行 import,我们才能够在第 6 行使用它。
Go 自带大量标准库包(涵盖格式化、I/O、字符串、网络等领域),你可以把它们引入自己的程序并复用,省去从零编写底层功能的麻烦。第 8 天安装 Go 后,编辑器中提示安装的扩展与依赖包,正是为了支持这类标准包的使用。
第 6 行:fmt.Println()
这里的fmt.Println()是向**标准输出(stdout)**写入文本的方式:无论可执行文件在哪里被成功运行,终端上都会显示括号内的消息。你完全可以自由修改()之间的内容,例如改成你自己的挑战标语。
从 2022/Days/Go/day11_example1.go 可以看到fmt.Println的更多用法——它可以同时接收多个参数:
package main import "fmt" func main() { var challenge = "#90DaysOfDevOps" fmt.Println("Welcome to", challenge, "") }这印证了fmt.Println是可变参数函数,可以一次性打印字符串与变量的组合,这也是它在 Go 入门教学中被高频使用的原因。
快速回顾(TLDR)
对照上面的逐行讲解,把 6 行代码的职责浓缩为一张速查清单:
- 第 1 行= 这个文件属于名为
main的包;必须叫main,因为它包含程序的入口点。 - 第 3 行= 为了使用
Println(),必须导入fmt包,这样它才能在第 6 行被调用。 - 第 5 行= 真正的起点,即
main函数。 - 第 6 行= 在系统上打印出
Hello #90DaysOfDevOps(或仓库中的"Until tomorrow #90DaysOfDevOps")。
这张清单可以作为你后续阅读任何 Go 程序的"起手式":先定位package main,再找func main(),再看 import 了哪些标准包、入口函数里调用了哪些函数。
下一步
掌握了编译、包与入口函数的机制之后,第 10 天将继续沿着 Go 语言的学习路径深入(参见 2022/Days/day10.md)。本仓库2022/Days/Go/目录下保存了后续多天(第 11~13 天)的示例源码,例如day11_example1.go~day13_example3.go,均可作为动手阅读与修改的练习材料;对应的逐日讲解见 2022/Days/day11.md、2022/Days/day12.md 与 2022/Days/day13.md。
- 文档/教程
【免费下载链接】90DaysOfDevOps
This repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.
相关推荐
90DaysOfDevOps 第 9 天:逐行拆解 Go 的 Hello World——编译、包与 main 函数入门
90DaysOfDevOps 第 9 天:逐行拆解 Go 的 Hello World——编译、包与 main 函数入门 本篇指南聚焦 90DaysOfDevOp
文档/教程90DaysOfDevOps 第九天:逐行拆解 Go 的 Hello World——编译、包与 main 函数入门
90DaysOfDevOps 第九天:逐行拆解 Go 的 Hello World——编译、包与 main 函数入门 本文是 90DaysOfDevOps 系列学
文档/教程90DaysOfDevOps 第 9 天:逐行拆解 Go Hello World——编译原理、包机制与 main 入口函数完全指南
90DaysOfDevOps 第 9 天:逐行拆解 Go Hello World——编译原理、包机制与 main 入口函数完全指南 本指南承接 Day 8 ht
文档/教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考