zoukankan      html  css  js  c++  java
  • 如何编写Go代码

    介绍

    本文讲解,如何在模块内部开发一个简单的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%goinhello.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
    $
  • 相关阅读:
    auto_ptr的VC版本源码剖析
    在VS2017中配置VLD(Visual Leak Detector)内存泄漏检测工具
    QT+VS中使用qDebug()打印调试信息无法显示
    QT+VS后中文字符乱码问题
    外观模式
    装饰模式(包装模式)
    组合模式
    桥接模式
    适配器模式
    单例模式
  • 原文地址:https://www.cnblogs.com/yaoshi641/p/15308491.html
Copyright © 2011-2022 走看看