• 如何写Go代码


    如何写Go代码

    一、介绍

    这篇文章演示在一个模块里面开发一个简单的Go包,并且介绍Go工具,标准的方法用于获取、构建、和下载Go模块,包和命令。

    注意:这篇文章假设你正在使用Go1.13或更新的版本,并且GO111MODULE环境变量没有设置。

    二、代码的组织

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

    一个仓库包含一个或多个模块。一个模块是一个相关Go包的集合,它们将一起发布。一个Go仓库通常只包含一个模块,位于仓库的根目录。一个被命名为go.mod的文件声明了模块的路径:模块中所有包的导入路径的前缀。一个模块包含的包在包含go.mod文件的目录下,也包含目录下的子目录,直到下一个包含go.mod文件的子目录(如果有)。

    注意:在你构建它之前,你不需要发布你的代码到远程仓库。一个模块能够被定义在本地不用归属于一个仓库。可是,组织你的代码就像你有一天会发布它一样是一个好习惯。

    每个模块路径不仅作为包的导入路径的前缀,而且指明go命令应该去哪下载它。例如,模块github.com/google/go-cmp包含一个包在comp/目录下。这个包的导入路径是github.com/google/go-cmp/cmp。标准库中的包没有模块路径前缀。

    三、你的第一个程序

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

    $ mkdir hello-write-go-code
    $ cd hello-write-go-code/
    $ ll
    total 0
    drwxr-xr-x   2 lifei  staff   64  9 18 11:01 ./
    drwxr-xr-x  12 lifei  staff  384  9 18 11:01 ../
    $ go mod init example/user/hello-write-go-code
    go: creating new go.mod: module example/user/hello-write-go-code
    $ ll
    total 8
    drwxr-xr-x   3 lifei  staff   96  9 18 11:02 ./
    drwxr-xr-x  12 lifei  staff  384  9 18 11:01 ../
    -rw-r--r--   1 lifei  staff   49  9 18 11:02 go.mod
    $
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Go 源文件中的第一条语句必须是包名。 可执行命令必须始终使用包 main。

    接下来,在目录中创建一个文件,命名为hello.go,并包含下面的代码:

    package main
    
    import "fmt"
    
    func main() {
      fmt.Println("Hello,world.")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    现在,你能够使用Go工具构建并安装这个程序:

    $ go install example/user/hello-write-go-code
    $
    
    • 1
    • 2

    这个命令,构建了一个hello-write-go-code命令,产生了一个可执行的二进制文件。它然后安装这个二进制文件在$HOME/go/bin/hello

    $ ll ~/go/bin/hello-write-go-code
    -rwxr-xr-x  1 lifei  staff  1854560  9 18 11:07 /Users/lifei/go/bin/hello-write-go-code*
    
    • 1
    • 2

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

    $ go env -w GOBIN=/somewhere/else/bin
    $
    
    • 1
    • 2

    要取消设置以前由 go env -w 设置的变量,请使用 go env -u:

    $ go env -u GOBIN
    $
    
    • 1
    • 2

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

    为方便起见,go 命令接受相对于工作目录的路径,如果没有给出其他路径,则默认为当前工作目录中的包。 所以在我们的工作目录中,下面的命令都是等价的:

    $ go install example/user/hello-write-go-code
    $ go install .
    $ go install
    $
    
    • 1
    • 2
    • 3
    • 4

    接下来,让我们运行程序确认它是工作的。为了添加方便,我们将添加安装目录到我们PATH,让二进制运行更容易:

    $ export PATH=$PATH:$(dirname $(go list -f '{{.Target}}' .))
    $ hello-write-go-code
    Hello,world.
    $
    
    • 1
    • 2
    • 3
    • 4

    如果你正在使用一个源代码控制系统,现在是时候初始化一个仓库。添加文件,并提交你的第一个改变。同样,这一步是可选的:您不需要使用源代码管理来编写 Go 代码。

    $ git add --all
    $ git commit
    [main 5e8eda6] 如何写一个Go代码
     3 files changed, 118 insertions(+)
     create mode 100644 document/2022-09-17-如何写Go代码.md
     create mode 100644 projects/hello-write-go-code/go.mod
     create mode 100644 projects/hello-write-go-code/hello.go
    $
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    go 命令通过请求相应的 HTTPS URL 并读取嵌入在 HTML 响应中的元数据来定位包含给定模块路径的存储库。许多托管服务已经为包含 Go 代码的存储库提供了该元数据,因此使您的模块可供他人使用的最简单方法通常是使其模块路径与存储库的 URL 匹配。

    四、从你的模块导入包

    让我们写一个morestrings程序,使用来自hello-write-go-code的程序。首先,创建一个目录作为包,命令为hello-write-go-code/morestrings,然后创建一个名称为reverse.go的文件,包含下面的内容:

    $ mkdir morestrings
    $ cd morestrings/
    $ touch reverse.go
    $
    
    • 1
    • 2
    • 3
    • 4
    package morestrings
    
    func ReverseRunes(s string) string {
      r := []rune(s)
      for i, j := 0, len(r)-1; i < j; i , j = i+1,j-1 {
        r[i], r[j] = r[j], r[i]
      }
      return string(r)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    因为我们的ReverseRunnes函数使用了大写字母开头,它是可导出的,并且能在其它包中使用,通过导入morestrings包:

    让我们测试这个包,使用go build编译:

    $ go build
    $ ll
    total 8
    drwxr-xr-x  3 lifei  staff   96  9 18 11:39 ./
    drwxr-xr-x  5 lifei  staff  160  9 18 11:39 ../
    -rw-r--r--  1 lifei  staff  174  9 18 11:46 reverse.go
    $
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这不会产生一个输出文件,相反,它保存编译包到本地的构建缓存中。

    之后,验证morestrings包的构建,让我们在hello程序中使用。为了做这个,修改hello-write-go-code/hello.go去使用morestrings包:

    package main
    
    import (
      "fmt"
      "example/user/hello-write-go-code/morestrings"
    )
    
    func main() {
      fmt.Println(morestrings.ReverseRunes("Hello,world."))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    安装Go程序,并运行新版本的程序,你应该看到一个新的,反转的消息。

    $ go install .
    $ hello-write-go-code
    .dlrow,olleH
    $
    
    • 1
    • 2
    • 3
    • 4

    五、从远程模块导入包

    导入路径可以描述如何使用 Git 或 Mercurial 等修订控制系统获取包源代码。go 工具使用此属性自动从远程存储库中获取包。例如,使用github.com/google/go-cmp/cmp在你的程序中。

    package main
    
    import (
      "fmt"
      "example/user/hello-write-go-code/morestrings"
      "github.com/google/go-cmp/cmp"
    )
    
    func main() {
      fmt.Println(morestrings.ReverseRunes("Hello,world."))
      fmt.Println(cmp.Diff("Hello World", "Hello Go"))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    现在你依赖额外的模块,你需要下载这个模块并记录它的版本在go.mod文件中。go mod tidy命令为导入的包添加缺少的模块要求,并删除不再使用的模块的要求。

    $ go mod tidy
    go: finding module for package github.com/google/go-cmp/cmp
    example/user/hello-write-go-code imports
    	github.com/google/go-cmp/cmp: module github.com/google/go-cmp/cmp: Get "https://proxy.golang.org/github.com/google/go-cmp/cmp/@v/list": dial tcp 142.251.42.241:443: i/o timeout
    $ go env -w GOPROXY=https://goproxy.cn
    $ go mod tidy
    go: finding module for package github.com/google/go-cmp/cmp
    go: downloading github.com/google/go-cmp v0.5.9
    go: found github.com/google/go-cmp/cmp in github.com/google/go-cmp v0.5.9
    $ go install example/user/hello-write-go-code
    $ hello-write-go-code
    .dlrow,olleH
      string(
    - 	"Hello World",
    + 	"Hello Go",
      )
    
    $ cat go.mod
    module example/user/hello-write-go-code
    
    go 1.18
    
    require github.com/google/go-cmp v0.5.9
    $
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    模块的依赖是自动被下载到pkg/mod目录下,这个目录是在环境变量GOPATH指定的。给定版本的模块下载的内容在需要该版本的所有其他模块之间共享,因此 go 命令将这些文件和目录标记为只读。 要删除所有下载的模块,您可以传递 -modcache 标志以进行清理:

    $ go clean -modcache
    $
    
    • 1
    • 2

    六、测试

    Go有一个轻量级的测试框架,组成go test命令和testing包。

    通过写一个带有_test.go结尾的文件,包含函数名TestXXX带有签名func (t *testing.T),测试框架会运行每一个函数。如果函数调用失败函数,例如 t.Error 或 t.Fail,则认为测试失败。

    添加一个测试到morestrings 包中,通过创建一个reverse_test.go,包含下面的代码:

    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)
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    然后使用go test运行测试:

    $ go test
    PASS
    ok  	example/user/hello-write-go-code/morestrings	0.687s
    $
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    Java集合容器面试题(2023最新版)
    SpringBoot+jSerialComm实现Java串口通信 读取串口数据以及发送数据
    MAX31855 热电偶温度传感器
    Spring的 webFlux 和 webMVC
    出现 conda虚拟环境默认放在C盘 解决方法
    智慧煤矿/智慧矿区视频汇聚存储与安全风险智能分析平台建设思路
    ubuntu20.04中安装配置docker nvidia容器来实现宿主机GPU的调用
    (数据科学学习手札141)利用Learn Git Branching轻松学习git常用操作
    1.3 do...while实现1+...100 for实现1+...100
    学习笔记-Nginx
  • 原文地址:https://blog.csdn.net/hefrankeleyn/article/details/126916296