90DaysOfDevOps 第 9 天:逐行拆解 Go 的 Hello World——编译、包与 main 函数入门

原创2026-09-30 18:40:081,741 阅读
文章标签:文档/教程

90DaysOfDevOps 第 9 天:逐行拆解 Go 的 Hello World——编译、包与 main 函数入门

本篇指南聚焦 90DaysOfDevOps 学习路线中 Go 语言的第一份真实代码:Hello #90DaysOfDevOps。在第 8 天完成 Go 安装与首个程序后,本文带你理解"编译"到底做了什么、Go 的包(package)机制如何组织代码,并逐行剖析 main.go 中每一行的职责与背后规则。读完你不仅能完全看懂这段 Hello World,还能掌握 go run、go build 的区别,以及为后续变量、数据类型等进阶内容打好地基。

从第 8 天说起:先有一个能跑的 Hello World

在 Día 8 中,我们完成了 Go 的安装、创建了工作目录,并在 src/Hello 下写出了第一份 main.go,最终用 go run main.go 与 go build main.go 让程序跑了起来。仓库中这份程序的本体位于 hello.go,全部代码只有 6 行:

package main

import "fmt"

func main() {
	fmt.Println("Until tomorrow #90DaysOfDevOps")
}

今天的工作,就是把这几行代码从"能运行"提升到"能看懂":它们分别解决了程序归属(package)、外部依赖(import)和执行入口(func main)三个核心问题。

什么是编译:从人类可读到机器可执行

Python、Java、Go、C++ 这类我们日常使用的语言都属于高级语言(high-level language),即对人友好的、可读的文本。但机器执行程序时,需要的是它能直接理解的形态——机器码(machine code)。把我们的人类可读代码翻译成机器码的这一动作,就叫做编译(compiling)。

编译流程可以概括为下图所示的过程:

Go 源码从人类可读代码编译为机器可执行二进制文件的流程示意图

对应到我们第 8 天的操作:我们创建了简单的 Hello World main.go,然后执行 go build main.go 编译出可执行文件。在 Windows 上编译后运行 ./main.exe,得到输出 Hello #90DaysOfDevOps。

如果对第 8 天的步骤感到陌生,可以回到 Día 8 重温安装与首个程序的创建过程。

编译、运行与交叉编译的三种姿势

在 Día 10 中,Go 工作区与编译运行方式被进一步展开,这里提前梳理三个核心命令:

  • go run:编译并运行命令行指定的 .go 文件所组成的 main 包,编译产物落在临时目录,运行完即弃,适合开发调试;
  • go build:编译当前目录下的包与依赖。若项目包含 main 包,会在当前目录生成可执行文件;否则产物放入 pkg 目录供其他 Go 程序导入使用。go build 还能为任何 Go 支持的平台生成可执行文件(交叉编译);
  • go install:行为与 go build 相同,但可执行文件会安装到 bin 目录。

仓库中的 makefile 正是交叉编译的实战样例——同一个 main.go 通过设置 GOARCH 与 GOOS 环境变量,一条命令产出五种平台的二进制:

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

这说明"编译"不只是把代码变成可执行文件,更是 Go 语言跨平台分发能力的基石——这也是 DevOps 场景下用 Go 构建 CLI 工具的一大优势。

什么是包:组织与复用代码的基本单元

包(package)是同一目录下、一起编译的源文件集合。更直白地说,一个包就是同一目录下的一组 .go 文件。还记得第 8 天的 Hello 文件夹吗?当你编写更复杂的 Go 程序时,可能会有 folder1、folder2、folder3…… 各自存放不同的 .go 文件,分别构成多个包,共同组装成完整程序。

我们使用包的最大动机是复用他人的代码:不必从零编写一切。假如你的程序需要一个计算器,很可能已经存在包含数学函数的现成 Go 包,把它导入自己的代码即可,省时省力——这正是代码共享与开源精神的体现。

Go 语言也鼓励你用包组织代码,让源码易于复用与维护。所有 .go 文件都必须属于某个包,且第一行必须书写 package <包名>。

Go 工作区的三大目录

结合 Día 10 的说明,Go 工作区(GOPATH)下三个目录各司其职:

  • src:存放所有 Go 程序与项目源码,负责 Go 仓库的命名空间与包管理,我们的 Hello 项目就在其中;
  • pkg:存放程序已安装(或曾安装)的包的归档文件,有助于加速编译过程;
  • bin:存放所有编译后的可执行二进制文件。

理解这个布局,才能明白 go build(产物在当前目录或 pkg)与 go install(产物进 bin)的差异从何而来。

Hello #90DaysOfDevOps 逐行拆解

现在回到我们的 main.go,逐行过一遍。完整代码文件见 hello.go,其整体结构如下:

Hello #90DaysOfDevOps 的 main.go 完整代码截图

第 1 行:package main——程序的归属与起点

第一行的 package main 表示此文件属于名为 main 的包。所有 .go 文件都必须归属某个包,并在首行写上 package 某名字。

包名可以任意起,但这里的包必须叫 main,因为该包包含程序的起始点——这是一条规则:main 包是 Go 程序的入口包,只有它才能被编译成可执行文件,而其他包则作为库被导入。

第 5 行:func main()——真正的执行入口

每当我们要编译并运行代码,必须告诉机器执行从哪里开始。我们通过编写名为 main 的函数做到这一点:机器会寻找名为 main 的函数作为程序入口。

函数(function)是一段能完成特定任务、可在整个程序中复用的代码块。 你可以用 func 关键字给函数起任何名字,但这里必须叫 main,因为它是代码开始执行的地方。第 5 行的 func main() { 就是入口函数本身(main 函数必须没有参数、没有返回值,且只能存在于 main 包中)。

第 3 行:import "fmt"——引入标准库

接着看第 3 行的导入语句:它表示你想把另一个包带入你的主程序。fmt 是 Go 提供的标准包(standard package),内含 Println() 函数;正因导入了它,我们才能在第 6 行使用 Println()。

Go 标准库提供了大量可直接引入、复用、免去从零编写的包,例如字符串处理、数学运算、文件操作、网络编程等。Go 官方标准库目录位于 Go Standard Library(https://pkg.go.dev/std)。注意:导入的包必须在代码中被使用,否则编译会报错——这与变量未使用报错同理,都是为了杜绝死代码。

第 6 行:fmt.Println("Until tomorrow #90DaysOfDevOps")——输出到标准输出

Println() 是一种把标准输出写入终端的方式——可执行文件在哪个终端被成功运行,输出就会显示在哪个终端。括号内的消息可以随意修改,比如改回教程中经典的 "Hello #90DaysOfDevOps"。第 6 行在终端打印这段文字,程序执行完毕。

TLDR:六行代码的速查表

  • 第 1 行(package main):此文件属于名为 main 的包;必须叫 main,因为它包含程序的入口点。
  • 第 3 行(import "fmt"):为了使用 Println(),必须导入 fmt 包,以便在第 6 行调用。
  • 第 5 行(func main()):真正的起点——main 函数。
  • 第 6 行(fmt.Println(...)):在系统终端打印 "Hello #90DaysOfDevOps" 等消息。

继续深入:变量、常量与数据类型

理解 Hello World 只是 Go 之旅的起点。在 Día 11 中,这段代码会被扩展成真正的"挑战天数统计"程序——引入 var challenge = "#90DaysOfDevOps" 变量、const daystotal = 90 常量与 dayscomplete 数据,并开始讲解 bool、数值、string 三类基本数据类型与 %T 格式化输出。仓库中的 day11_example1.go 等示例文件展示了从 Hello World 向实际应用的演化过程。

至此,你已经能够完整解读 Go 的第一个程序:理解编译的本质、包的组织方式、main 包的入口规则、标准库导入与输出函数的使用。下一步(Día 10)我们将深入 Go 工作区与编译运行工具链,请继续在 Día 10 相见。

登录后查看全文
90DaysOfDevOps