介绍
本文讲解, 如何在模块内部开发一个简单的 Go 包, 如何使用 Go 工具, 分发, 构建, 安装 Go 模块, 包, 和命令行
注意, 本文假设你使用的是 Go1.13 以上版本, 并且 GO111MODULE 环境变量没有设置. 如果你需要老版本的教程, 可以看这里...
代码组织结构
Go 程序是由包组成的, 一个包是把同一个路径下的源文件合集编译在一起, 在一个文件内定义的函数, 类型, 变量和常量, 对同一个包下的其他文件也是可见的
存储库包含一个或多个模块. 模块是一起发布的相关 Go 包的集合. Go 存储库通常只包含一个模块, 位于存储库的根目录下. 在 go.mod 文件内声明了模块路径: 模块内所有包的导入路径前缀, 该模块包含 go.mod 文件的目录中的包以及该目录的子目录, 直到包含另一个 go.mod 文件的下一个子目录<不太理解, 绕弯弯的话>
注意, 你并不需要在你构建你的代码之前, 将其发布到远端仓库中, 模块是能定义在本地端, 并不需要仓库. 不过呢, 使用仓库来管理你的代码是个很好的习惯, 就如同你在未来某天会用到他.
每个模块的路径不仅作为其包的导入路径前缀, 而且还指示 go 命令应该在哪里下载它, 比如, 为了下载模块 golang.org/x/tools,go 命令将参考 https://golang.org/x/tools (这里有更多描述).
import 路径是个字符串, 用来导入一个包, 包的导入路径是其模块路径与模块内的子目录组合, 例如, 模块 GitHub.com/google/go-cmp 在目录 cmp / 中包含一个包. 该包的导入路径是 GitHub.com/google/go-cmp/cmp. 标准库中的包没有模块路径前缀.
你的第一个程序
编译和运行这个简单程序, 首先, 选择一个模块路径(我们使用 example/user/hello), 然后创建 go.mod 文件
- $ mkdir hello # Alternatively, clone it if it already exists in version control.
- $ cd hello
- $ go mod init example/user/hello
- go: creating new go.mod: module example/user/hello
- $ cat go.mod
- module example/user/hello
- go 1.16
- $
在 Go 源文件中, 第一行必须是 package name , 使用的命令必须是 package main
接下来, 创建一个名为 hello.go 的文件,
- package main
- import "fmt"
- func main() {
- fmt.Println("Hello, world.")
- }
现在, 你就能构建并安装这个程序了
- $ go install example/user/hello
- $
这个命令是构建 hello 为可执行程序的命令, 它会将可执行文件安装到 $HOME/go/bin/hello 目录下(在 Windows 系统下, 是 %USERPROFILE%\go\bin\hello.exe)
安装路径的配置是在 GOPATH 和 GOBIn 环境变量中, 如果 GOBIN 被设置了, 可执行文件会安装的这个目录下, 如果 GOPATH 设置了, 那么可执行文件会被安装到 bin 目录下, 如果 bin 目录不存在就会安装到 GOPATH($HOME/Go 或者 %USERPROFILE%\GO)目录下. <注: 我测试后, GOBIN 的优先级高于 GOPATH>
使用 go env 命令, 用来查看和设置环境变量
- $ go env -w GOBIN=/somewhere/else/bin
- $
取消之前用 go env- w 设置的值, 可以使用 go env -u < 其实就是回到默认值>
$ go env -u GOBIN $
像 go install 这样的命令在包含当前工作目录的模块上下文中应用, 如果工作目录不在 example/user/hello 模块中, go install 可能会失败. 为了方便起见, go 命令接受相对于工作目录的路径, 如果没有提供其他路径, 则默认为当前工作目录中的包. 因此, 在我们的工作目录中, 以下命令都是等效的
$ go install example/user/hello
$ go install .
$ go install
接下来, 让我们运行该程序以确保其正常工作. 为了更加方便, 我们将把安装目录添加到路径中, 以使运行二进制文件更加容易:
- # Windows users should consult https://github.com/golang/go/wiki/SettingGOPATH
- # for setting %PATH%.
- $ export PATH=$PATH:$(dirname $(go list -f '{{.Target}}' .))
- $ hello
- Hello, world.
- $
如果您使用的是源代码管理系统, 那么现在正是初始化存储库, 添加文件和提交第一次更改的好时机. 同样, 此步骤是可选的: 您不需要使用源代码管理来编写 Go 代码.
- $ Git init
- Initialized empty Git repository in /home/user/hello/.Git/
- $ Git add go.mod hello.go
- $ Git commit -m "initial commit"
- [master (root-commit) 0b4507d] initial commit
- 1 file changed, 7 insertion(+)
- create mode 100644 go.mod hello.go
- $
go 命令通过包括在模块中的库位置, 来定位请求对应的 https 地址, 来读取嵌入在 html 请求中的元数据, 有许多主机服务, 已经能提供包含 Go 代码的元数据仓库, 所以, 你能很轻松的让其他人使用,
从你的模块中引入包
让我们编写一个 morestrings 包, 让它能在 hello 程序中使用. 首先, 为这个包创建路径, 命名为: $HOME/hello/morestrings, 然后命名文件名叫 reverse.go:
- // Package morestrings implements additional functions to manipulate UTF-8
- // encoded strings, beyond what is provided in the standard "strings" package.
- package morestrings
- // ReverseRunes returns its argument string reversed rune-wise left to right.
- 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)
- }
因为我们的 ReverseRunes 函数以大写字母开头, 所以它被导出, 并且可以在导入 morestrings 包的其他包中使用.
- $ cd $HOME/hello/morestrings
- $ go build
- $
这一步, 不会产生文件输出, 它将编译后的包保存在本地生成缓存中.
在确认 morestrings 包已生成之后, 让我们从 hello 程序中使用它. 为此, 请修改原始 $HOME/hello/hello.go 以使用 morestrings 包:
- package main
- import (
- "fmt"
- "example/user/hello/morestrings"
- )
- func main() {
- fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
- }
- $ go install example/user/hello
- $ hello Hello, Go!
安装远端模块的包
导入路径可以描述如何使用修订控制系统 (如 Git 或 Mercurial) 获取包源代码, go 工具使用此属性自动从远程存储库获取包. 例如, 要在程序中使用 GitHub.com/google/go-cmp/cmp:
- package main
- import (
- "fmt"
- "example/user/hello/morestrings"
- "github.com/google/go-cmp/cmp"
- )
- func main() {
- fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
- fmt.Println(cmp.Diff("Hello World", "Hello Go"))
- }
现在您已经依赖于外部模块, 您需要下载该模块并在 go.mod 文件中记录其版本, go mod tidy 命令为导入的包添加缺少的模块需求, 并删除不再使用的模块上的需求.
- $ go mod tidy
- go: finding module for package GitHub.com/google/go-cmp/cmp
- go: found GitHub.com/google/go-cmp/cmp in GitHub.com/google/go-cmp v0.5.4
- $ go install example/user/hello
- $ hello
- Hello, Go!
- string(
- - "Hello World",
- + "Hello Go",
- )
- $ cat go.mod
- module example/user/hello
- go 1.16
- require GitHub.com/google/go-cmp v0.5.4
- $
模块依赖项将自动下载到 GOPATH 环境变量指示的目录的 pkg/mod 子目录中. 给定版本的模块的下载内容在需要该版本的所有其他模块之间共享, 因此 go 命令将这些文件和目录标记为只读. 要删除所有下载的模块, 可以传递 - modcache 标志以清除:
- $ go clean -modcache
- $
测试
Go 有一个轻量级测试框架, 由 Go-test 命令和测试包组成
您可以通过创建一个名称以_test.go 结尾的文件来编写测试, 该文件包含名为 TestXXX 且带有签名 func(t*testing.t)的函数. 测试框架运行每个这样的功能; 如果函数调用失败函数, 如 t.Error 或 t.Fail, 则认为测试失败
通过创建包含以下 go 代码的文件 $HOME/hello/morestrings/reverse_test.go, 将测试添加到 morestrings 包中.
- package morestrings
- import "testing"
- func TestReverseRunes(t *testing.T) {
- cases := []struct {
- in, want string
- }{
- {"Hello, world", "dlrow ,olleH"},
- {"Hello, 世界", "界世 ,olleH"},
- {"",""},
- }
- for _, c := range cases {
- got := ReverseRunes(c.in)
- if got != c.want {
- t.Errorf("ReverseRunes(%q) == %q, want %q", c.in, got, c.want)
- }
- }
- }
- $ cd $HOME/hello/morestrings
- $ go test
- PASS
- ok example/user/hello/morestrings 0.165s
- $
来源: http://www.bubuko.com/infodetail-3829259.html