Go 编程实战系列(四)
在前面的文章中,我们已经完成了 Go 开发环境安装,并配置了 GoLand 或 VS Code。接下来,我们将正式编写第一个 Go 程序。
几乎每一种编程语言的学习,都会从"Hello World"开始。虽然这个程序非常简单,但它包含了 Go 可执行程序最基本的组成部分,例如包声明、依赖导入、主函数和标准输出。
本文不仅会带你运行 Hello World,还会逐行分析代码,并介绍 Go 程序从源码到运行结果的完整过程。
一、创建 Go 项目
首先选择一个用于保存项目的目录。
例如,在终端中执行:
bash
mkdir hello-go
cd hello-go
Windows 用户也可以在某个磁盘下创建项目:
go
mkdir D:\go-projects\hello-go
cd D:\go-projects\hello-go
进入项目目录后,执行:
go
go mod init hello-go
终端会输出:
go
go: creating new go.mod: module hello-go
此时项目目录中会生成一个 go.mod 文件:
go
hello-go
└── go.mod
go.mod 是 Go Modules 的核心文件,用于记录当前项目的模块名称、Go 版本以及第三方依赖。
文件内容大致如下:
go
module hello-go
go 1.xx
其中,module hello-go 表示当前项目的模块名称。
关于 Go Modules 的详细内容,我们会在下一篇文章中专门讲解。
二、创建 main.go 文件
在项目根目录中新建一个名为 main.go 的文件。
项目结构变为:
go
hello-go
├── go.mod
└── main.go
在 main.go 中写入以下代码:
go
package main
import "fmt"
func main() {
fmt.Println("Hello World")
}
保存文件后,在终端执行:
arduino
go run .
输出结果为:
Hello World
至此,第一个 Go 程序已经成功运行。
三、逐行分析 Hello World
虽然代码只有几行,但每一部分都有明确的作用。
1. package main
第一行代码是:
css
package main
Go 使用包组织代码,每一个 Go 源文件都必须声明自己属于哪个包。
这里的包名是:
css
main
main 是一个特殊的包名。
当一个项目需要编译成可以直接运行的程序时,必须包含 main 包,同时还必须包含一个 main 函数。
例如:
go
package main
func main() {
}
如果使用其他包名,例如:
go
package hello
这个包通常会被当作代码库使用,不能直接作为独立程序运行。
因此,可以简单理解为:
-
package main:表示这是一个可执行程序; -
其他包名:通常表示这是一个可以被其他代码调用的功能包。
2. import "fmt"
第二部分代码是:
arduino
import "fmt"
import 用于导入其他包。
这里导入的是 Go 标准库中的 fmt 包。fmt 是 format 的缩写,主要用于格式化输入和输出。
它提供了很多常用函数,例如:
scss
fmt.Print()
fmt.Println()
fmt.Printf()
fmt.Sprintf()
fmt.Scan()
其中:
-
Print:输出内容,不自动换行; -
Println:输出内容并自动换行; -
Printf:按照指定格式输出; -
Sprintf:格式化字符串并返回结果; -
Scan:读取用户输入。
在当前程序中,我们使用了:
arduino
fmt.Println("Hello World")
因此必须先导入 fmt 包。
如果删除导入语句,程序就会报错:
bash
undefined: fmt
因为编译器不知道 fmt 是什么。
3. func main()
接下来是:
csharp
func main() {
}
func 是定义函数的关键字。
基本格式如下:
go
func 函数名() {
函数代码
}
这里定义的函数名为 main。
main 函数是 Go 可执行程序的入口。当程序启动时,会自动从 main 函数开始执行。
需要注意,main 函数必须满足以下条件:
-
必须位于
main包中; -
函数名必须是
main; -
不能带参数;
-
不能声明返回值。
正确写法:
csharp
func main() {
}
下面的写法不能作为程序入口:
csharp
func Main() {
}
Go 区分大小写,Main 和 main 是两个不同的名称。
4. fmt.Println()
函数中的代码是:
arduino
fmt.Println("Hello World")
这行代码调用了 fmt 包中的 Println 函数。
在 Go 中,调用其他包中的公开函数,通常采用以下格式:
scss
包名.函数名()
因此:
scss
fmt.Println()
表示调用 fmt 包中的 Println 函数。
括号中的:
arduino
"Hello World"
是一个字符串。
Go 字符串通常使用双引号包裹:
arduino
"你好,Go"
arduino
"学习 Go 编程"
arduino
"Hello World"
程序运行后,字符串会被输出到终端。
四、使用 go run 运行程序
运行 Go 程序最简单的方式是:
arduino
go run .
这里的点号表示当前目录。
Go 会找到当前目录中的 Go 源文件,临时完成编译,然后运行程序。
也可以直接指定文件:
go
go run main.go
对于当前只有一个文件的项目,两种方式都可以。
但随着项目规模扩大,一个项目中可能包含多个 Go 文件。因此,更推荐使用:
arduino
go run .
需要注意,go run 主要用于开发和测试。它不会在当前目录中留下最终的可执行文件。
五、使用 go build 编译程序
除了直接运行,还可以将 Go 源代码编译成可执行程序:
go
go build
编译完成后,当前目录会生成可执行文件。
Windows 系统通常生成:
go
hello-go.exe
macOS 和 Linux 通常生成:
go
hello-go
在 Windows 中运行:
go
.\hello-go.exe
在 macOS 或 Linux 中运行:
bash
./hello-go
输出同样是:
Hello World
还可以使用 -o 参数指定生成的文件名称:
go
go build -o hello
Windows 下可以执行:
go
go build -o hello.exe
go build 与 go run 的主要区别是:
-
go run:临时编译并立即运行; -
go build:生成可长期保存和部署的可执行文件。
Go 编译出的程序通常不需要目标服务器额外安装 Go 环境,这也是 Go 部署方便的重要原因。
六、修改输出内容
可以尝试修改程序,让它输出多行内容:
go
package main
import "fmt"
func main() {
fmt.Println("Hello World")
fmt.Println("这是我的第一个 Go 程序")
fmt.Println("开始学习 Go 编程")
}
运行:
arduino
go run .
输出:
Hello World
这是我的第一个 Go 程序
开始学习 Go 编程
也可以在一次调用中传入多个内容:
go
package main
import "fmt"
func main() {
name := "Go"
fmt.Println("Hello", name)
}
输出:
Hello Go
Println 会在多个参数之间自动添加空格,并在末尾自动换行。
七、使用 Printf 格式化输出
除了 Println,开发中还经常使用 Printf。
示例:
go
package main
import "fmt"
func main() {
name := "Go"
year := 2009
fmt.Printf("%s 语言于 %d 年正式发布\n", name, year)
}
运行结果:
yaml
Go 语言于 2009 年正式发布
这里使用了格式占位符:
-
%s:字符串; -
%d:整数; -
\n:换行。
Printf 不会像 Println 一样自动换行,所以通常需要手动加入 \n。
八、Go 代码为什么不需要分号?
学习过 C、C++、Java 或 JavaScript 的开发者,可能会发现 Go 代码末尾没有分号:
arduino
fmt.Println("Hello World")
而不是:
arduino
fmt.Println("Hello World");
实际上,Go 语法内部仍然存在分号规则,但编译器通常会自动补充,因此开发者不需要手动书写。
统一省略分号能够让代码更加简洁,也能减少不一致的代码风格。
九、Go 对代码格式的要求
Go 非常强调统一的代码格式。
例如,下面的代码虽然看起来很乱:
go
package main
import "fmt"
func main(){fmt.Println("Hello World")}
但执行格式化命令:
css
gofmt -w main.go
之后会自动变为:
go
package main
import "fmt"
func main() {
fmt.Println("Hello World")
}
如果使用 GoLand 或 VS Code,还可以开启保存时自动格式化。
Go 官方通过 gofmt 统一代码风格,使不同开发者编写的代码保持相似结构,降低团队协作和代码阅读成本。
十、常见错误
1. 找不到 go.mod
执行 go run . 时可能提示:
go
go: go.mod file not found
解决方法是在项目目录执行:
go
go mod init hello-go
2. package 拼写错误
错误代码:
css
pakage main
正确代码:
css
package main
Go 关键字不能随意拼写。
3. main 函数大小写错误
错误写法:
csharp
func Main() {
}
正确写法:
csharp
func main() {
}
Go 区分大小写。
4. 导入了包却没有使用
例如:
go
package main
import "fmt"
func main() {
}
运行时会提示:
arduino
"fmt" imported and not used
Go 不允许存在未使用的导入包。要么使用 fmt,要么删除导入语句。
5. 字符串使用了错误引号
错误写法:
scss
fmt.Println("Hello World")
这里使用的是中文弯引号,Go 无法识别。
正确写法:
arduino
fmt.Println("Hello World")
编写代码时必须使用英文符号。
十一、本章小结
本篇完成了第一个 Go 程序 Hello World,并分析了 Go 可执行程序的基本结构。
主要知识点包括:
-
使用
go mod init初始化项目; -
使用
package main声明可执行程序; -
使用
import导入标准库; -
main函数是程序入口; -
使用
fmt.Println输出内容; -
使用
go run .运行程序; -
使用
go build编译可执行文件; -
使用
gofmt格式化代码; -
Go 不允许存在未使用的导入包。
Hello World 虽然简单,却包含了 Go 程序最核心的基本结构。后续无论开发命令行工具、Web 服务还是微服务项目,都将从类似的代码结构开始。
本章练习
- 创建一个名为
hello-go的项目。 - 初始化项目并生成
go.mod。 - 使用
Println输出姓名和学习目标。 - 使用
Printf输出一个字符串和一个整数。 - 使用
go run .运行程序。 - 使用
go build编译程序。 - 使用
gofmt格式化代码。 - 故意导入一个未使用的包,观察编译器提示。
下一篇预告
《Go Modules 包管理详解》
下一篇将介绍现代 Go 项目的依赖管理方式,包括 go.mod、go.sum、模块路径、依赖下载、版本管理、go get、go mod tidy、模块代理以及常见依赖问题的解决方法。