【Go语言成长之路】如何编写Go代码

发布于:2024-11-27 ⋅ 阅读:(149) ⋅ 点赞:(0)

如何编写Go代码

一、介绍

​ 本文档演示了模块内简单 Go 包的开发,并介绍了 go tool、以及标准的获取、构建和安装 Go 模块、包和命令的标准方法。

二、代码组织

​ Go程序被组织成包,一个Package是同一目录中编译在一起的源文件的集合。一个源文件中定义的函数、类型、变量和常量对于同一包中的所有其他源文件都是可见的。

​ 存储库(repository)包含一个或者多个模块,模块是一起发布的相关 Go 包的集合。Go 存储库通常只包含一个模块,位于存储库的根目录下。名为 go.mod 的文件声明了模块路径:模块内所有包的导入路径前缀。该模块包含包含其 go.mod 文件的目录中的包以及该目录的子目录,直到包含另一个 go.mod 文件(如果有)的下一个子目录。

​ 导入路径是用于导入包的字符串。包的导入路径是其模块路径及其在模块内的子目录的连接。例如,模块 github.com/google/go-cmp 包含目录 cmp/ 中的包。该包的导入路径是 github.com/google/go-cmp/cmp。标准库中的包没有模块路径前缀。

三、第一个程序

要编译并运行一个简单的程序,首先选择一个模块路径(我们将使用 example/user/hello)并创建一个声明它的 go.mod 文件:

~$ mkdir hello
~$ cd hello/
~/hello$ go mod init example.com/user/hello
go: creating new go.mod: module example.com/user/hello
~/hello$ cat go.mod 
module example.com/user/hello

go 1.23.0

Go源文件中的第一条语句必须是包名。可执行命令必须始终使用包 main。接下来,在hello目录中创建一个名为 hello.go 的文件,其中包含以下 Go 代码:

package main

import "fmt"

func main() {
    fmt.Println("Hello, world.")
}

现在您可以使用 go 工具构建并安装该程序:

$ go install .

​ 安装目录由 GOPATHGOBIN 环境变量控制。如果设置了 GOBIN,二进制文件将安装到该目录。如果设置了 GOPATH,则二进制文件将安装到 GOPATH 列表中第一个目录的 bin 子目录中。否则,二进制文件将安装到默认 GOPATH 的 bin 子目录($HOME/go 或 %USERPROFILE%\go)。

​ 您可以使用 go env 命令为将来的 go 命令可移植地设置环境变量的默认值:

$ go env -w GOBIN=/somewhere/else/bin
$ go env -u GOBIN # 取消之前的变量设置

注:像 go install 这样的命令适用于包含当前工作目录的模块的上下文。如果工作目录不在 example/user/hello 模块内,go install 可能会失败。

​ 为了更加方便,我们将安装目录添加到我们的 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

四、从模块导入包

让我们编写一个 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 包的其他包中使用。

让我们测试一下该包是否使用 go build 进行编译:

$ 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!
$ 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.Errort.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)
        }
    }
}

然后使用 go test 运行测试:

$ cd $HOME/hello/morestrings
$ go test
PASS
ok  	example/user/hello/morestrings 0.165s
$

网站公告

今日签到

点亮在社区的每一天
去签到