本文档演示了一个模块(Module)内部简单 Go 软件包(Package)的开发过程,并介绍了 go 工具------这是获取、构建和安装 Go 模块、软件包及命令的标准方式。
📂 代码组织 (Code Organization)
Go 程序由"包"组成。 一个包是同一目录中被一起编译的一组源文件。在一个源文件中定义的函数、类型、变量和常量,对同一包内的所有其他源文件都是可见的。
一个代码仓库包含一个或多个模块。 模块是共同发布的一组相关 Go 包的集合。Go 仓库通常只包含一个位于根目录的模块。名为 go.mod 的文件声明了模块路径(Module Path) :它是该模块内所有包的导入路径前缀。模块包含 go.mod 所在目录及其子目录下的所有包,直到遇到另一个包含 go.mod 的子目录为止。
注意: 在构建代码之前,你不必将其发布到远程仓库。模块可以在本地定义。不过,像将来要发布一样去组织代码是一个好习惯。
模块路径 不仅是导入路径的前缀,还指示了 go 命令应该去哪里下载它。例如,下载 golang.org/x/tools 模块时,go 命令会查阅由该 URL 指定的仓库。
导入路径(Import Path) 是用于导入包的字符串。包的导入路径由其"模块路径"加上其在模块内的"子目录路径"组成。例如,模块 github.com/google/go-cmp 在 cmp/ 目录下包含一个包,则该包的导入路径为 github.com/google/go-cmp/cmp。标准库中的包没有模块路径前缀。
🚀 你的第一个程序 (Your First Program)
要编译并运行一个简单的程序,首先选择一个模块路径(我们使用 example/user/hello)并创建一个声明它的 go.mod 文件:
Bash
$ mkdir hello
$ cd hello
$ go mod init example/user/hello
go: creating new go.mod: module example/user/hello
Go 源文件的第一行必须是 package <名称>。可执行命令必须始终使用 package main。 在目录下创建 hello.go:
Go
package main
import "fmt"
func main() {
fmt.Println("Hello, world.")
}
使用 go 工具安装该程序:
Bash
$ go install example/user/hello
该命令会生成一个二进制文件,并安装到 $HOME/go/bin/hello。安装目录受 GOPATH 和 GOBIN 环境变量控制。你可以使用 go env -w 来设置变量:
Bash
$ go env -w GOBIN=/somewhere/else/bin
📦 导入模块内的包 (Importing packages from your module)
让我们编写一个 morestrings 包。创建目录 $HOME/hello/morestrings,并创建 reverse.go:
Go
package morestrings
// ReverseRunes 将字符串按 rune 反转。
// 函数名首字母大写表示它是导出的(Exported)。
func ReverseRunes(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
回到 hello.go 中调用它:
Go
import (
"fmt"
"example/user/hello/morestrings"
)
func main() {
fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
}
🌐 导入远程模块 (Importing packages from remote modules)
go 工具可以自动从远程仓库(如 Git)获取包。例如,要在程序中使用 go-cmp:
Go
import "github.com/google/go-cmp/cmp"
当你添加了外部依赖后,运行以下命令来下载并记录版本:
Bash
$ go mod tidy
这会更新你的 go.mod 并下载依赖到本地缓存。
🧪 测试 (Testing)
Go 拥有一个轻量级的测试框架,由 go test 命令和 testing 包组成。 测试文件必须以 _test.go 结尾,函数签名必须为 func TestXXX(t *testing.T)。
为 morestrings 创建 reverse_test.go:
Go
func TestReverseRunes(t *testing.T) {
// ... 测试逻辑 ...
}
运行测试:
Bash
$ go test
PASS
ok example/user/hello/morestrings 0.165s