blog

首页 / go语言 / 如何写go语言

如何写go语言

转自https://golang.org/doc/code.html

介绍

这份文档演示简单的go语言包开发并且介绍[go]工具(https://golang.org/cmd/go/),fetch,build和安装go包以及命令的标准方式。

go工具需要你在指定的方式组织你的代码。请仔细阅读这篇文档。它解释了启动并运行你的go安装最简单的方式。

有一个视频也是类似的解释

代码组织

概览

注意,这里有别于其他的编程语言环境,每一个工程都有一个独立的工作区并且工作区与版本的控制库紧紧相连

工作区

工作区是一个层次目录,其根目录有两个文件夹

go工具构建二进制文件并且向bin文件夹安装二进制文件

src的子目录一般包含多个版本控制的存储库,用于跟踪一个或多个源包的开发。

为了让您了解工作区在实践中的外观,以下是一个示例:

bin/
    hello                          # command executable
    outyet                         # command executable
src/
    github.com/golang/example/
        .git/                      # Git repository metadata
	hello/
	    hello.go               # command source
	outyet/
	    main.go                # command source
	    main_test.go           # test source
	stringutil/
	    reverse.go             # package source
	    reverse_test.go        # test source
    golang.org/x/image/
        .git/                      # Git repository metadata
	bmp/
	    reader.go              # package source
	    writer.go              # package source
    ... (many more repositories and packages omitted) ...

上面的树展示一个工作区包含两个存储库(example和image)。这个example存储库包含两个命令(hello和outyet)和一个库(stringutil)。这个image存储库包含bmp包和其他若干

一个典型的工作区包含许多源存储库,源存储库包含许多包和命令。大部分go编程者保持所有他们的go源代码并且依赖于一个单独的工作区。

请注意,不应使用符号链接将文件或目录链接到工作区。

命令和库是从不同类型的源包构建的。 我们稍后会讨论这种区别。

GOPATH环境变量

GOPATH环境变量指定你工作区的位置。它默认是在你home文件下的go文件夹,因此$HOME/go on Unix$home/go on Plan 9, 和 %USERPROFILE%\go (usually C:\Users\YourName\go) on Windows

假如你喜欢在不同的地方工作,你将需要设置GOPATH为目标路径。注意GOPATH一定不能是你go的安装目录。

命令go env GOPATH 打印当前有效的GOPATH;如果环境变量未设置,他打印默认的定位

为了方便,增加工作区子目录bin在你的PATH中

$ export PATH=$PATH:$(go env GOPATH)/bin

为简洁起见,本文档其余部分中的脚本使用$ GOPATH而不是$ go env GOPATH。 如果你没有设置GOPATH,要使脚本以书面形式运行,你可以在这些命令中替换$ HOME / go,否则运行:

$ export GOPATH=$(go env GOPATH)

为了学习更多关于GOPATH环境变量的值,参看go help gopath

使用自定义工作区位置,设置环境变量

导入路径

导入路径是唯一标识包的字符串。包的导入路径对应于其在工作空间内或远程存储库中的位置(解释如下)

来自于标准库的包给予简短的导入路径,比如fmt,net/http。对于你自己的包,你必须选择基础路径,该路径不太可能与将来添加到标准库或其他外部库中发生冲突。

如果你保持你代码在源存储的什么地方,你将使用源存储库的根作为你的基础路径。目前,如果你有github账户在github.com/user,这将是你的基础路径

请注意,在构建代码之前,无需将代码发布到远程存储库。 组织代码只是一个好习惯,好像有一天你会发布它一样。 实际上,您可以选择任意路径名称,只要它对标准库和更大的Go生态系统是唯一的。

我们将使用github.com/user 作为我们的基础路径,创建一个文件夹在你的工作区保存源代码

mkdir -p $GOPATH/src/github.com/user

第一个程序

编译运行一个简单的程序,首先选择一个包的路径(我们将使用github.com/user/hello)并且穿件对应的包文件夹在你的工作区

$ mkdir $GOPATH/src/github.com/user/hello

接下来,创建一个名为hello.go的文件在hello文件夹下,包含以下go代码

package main

import "fmt"

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

现在,你可以使用go工具构建并且安装这个程序了

$ go install github.com/user/hello

注意,你可以运行这个命令在你系统的任何地方。这个go工具通过指定的GOPATH的工作区目录下的github.com/user/hello包找到源代码

你也可以忽略包路径如果你运行go install在包目录下

$ cd $GOPATH/src/github.com/user/hello
$ go install

这个命令构建hello命令,产生一个可执行的二进制。它将会安装在工作区的bin目录下,(在window为,hello.exe)在我们的例子,它将会是$GOPATH/bin/hello$HOME/go/bin/hello

你可以运行该程序,通过输入完成的路径

$ $GOPATH/bin/hello
Hello, world.

或者,你可以增加$GOPATH/bin/在你的PATH中,仅仅输入二进制名称就可执行

$ hello
Hello, world.

如果你使用源控制系统,现在是好时间去初始化存储库,增加文件,并且提交你第一次改变。再一次,这一步是额外的,你不需要使用源控制器去写go代码

$ cd $GOPATH/src/github.com/user/hello
$ git init
Initialized empty Git repository in /home/user/work/src/github.com/user/hello/.git/
$ git add hello.go
$ git commit -m "initial commit"
[master (root-commit) 0b4507d] initial commit
 1 file changed, 1 insertion(+)
  create mode 100644 hello.go

第一个二进制

一起写一个二进制并且在hello程序中使用它。

再一次,在第一步是选择包的路径(我们将使用github.com/user/stringutil)并且创建包文件夹

$ mkdir $GOPATH/src/github.com/user/stringutil

接下来,创建一个文件命名为reverse.go并且键入如下内容

// Package stringutil contains utility functions for working with strings.
package stringutil

// Reverse returns its argument string reversed rune-wise left to right.
func Reverse(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)
}

现在,测试包使用go build编译:

$ go build github.com/user/stringutil

或者,如果你在包的源目录下,仅仅执行

$ go build

这不会产生输出文件。取而代之的是它保存一个编译的包在本地构建缓存中。 确认完stringutil包构建后,修改你原版的hello.go(在$GOPATH/src/github.com/user/hello)

package main

import (
    "fmt"
    "github.com/user/stringutil"
)

func main() {
    fmt.Println(stringutil.Reverse("!oG ,olleH"))
}

安装hello程序

$ go install github.com/user/hello

运行一个新版本的程序,你将会看到新的信息

$ hello
Hello, Go!

在上述步骤后,你的工作区就像下面

bin/
    hello                 # command executable
src/
    github.com/user/
        hello/
            hello.go      # command source
        stringutil/
            reverse.go    # package source

包名称

第一句语句在go的源文件必须是package name

这个name是包的默认导入名称(所有文件在包中必须使用相同的name

Go的约定是包名称是导入路径的最后一个元素:导入为“crypto / rot13”的包应命名为rot13。

可执行命令必须始终使用package main

不要求包名称在链接到单个二进制文件的所有包中都是唯一的,只要导入路径(它们的完整文件名)是唯一的。

请参阅Effective Go以了解有关Go的命名约定的更多信息。

测试

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

你可以通过创建以_test.go为结尾的文件编写测试。它包含签名函数为TestXXXfunc(t *testing.T)。测试框架运行在每一个这样的函数;如果函数执行失败,比如t.Error或者t.Fail,这个测试被认为是失败了。

增加测试给stringutil包通过创建文件在 $GOPATH/src/github.com/user/stringutil/reverse_test.go中,并且包含以下内容

package stringutil

import "testing"

func TestReverse(t *testing.T) {
    cases := []struct {
        in, want string
    }{
        {"Hello, world", "dlrow ,olleH"},
        {"Hello, 世界", "界世 ,olleH"},
        {"", ""},
    }
    for _, c := range cases {
        got := Reverse(c.in)
        if got != c.want {
            t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want)
        }
    }
}

然后使用go test运行测试

$ go test github.com/user/stringutil
ok    github.com/user/stringutil 0.165s

一如既往,如果你运行go工具从包文件夹中,你可以忽略包路径

$ go test
ok    github.com/user/stringutil 0.165s

使用go help test可以查看测试包文档

远程包

导入路径可以描述如何使用诸如Git或Mercurial之类的修订控制系统来获取包源代码。

go工具使用此属性自动从远程存储库获取包。 例如,本文档中描述的示例也保存在GitHub上托管的Git存储库中github.com/golang/example如果您在包的导入路径中包含存储库URL,那么go get将自动获取,构建和安装它:

$ go get github.com/golang/example/hello
$ $GOPATH/bin/hello
Hello, Go examples!

如果工作空间中不存在指定的包,go get 会将它放在GOPATH指定的第一个工作空间内。(如果该包已经存在,go get跳过远程拉取,其行为与go install一样)

发出上面的go get命令后,工作区目录树现在应如下所示:

bin/
    hello                           # command executable
src/
    github.com/golang/example/
    .git/                       # Git repository metadata
        hello/
            hello.go                # command source
        stringutil/
            reverse.go              # package source
            reverse_test.go         # test source
    github.com/user/
        hello/
            hello.go                # command source
        stringutil/
            reverse.go              # package source
            reverse_test.go         # test source

在GitHub上托管的hello命令取决于同一存储库中的stringutil包。 hello.go文件中的导入使用相同的导入路径约定,因此go get命令也能够找到并安装依赖包。`

import "github.com/golang/example/stringutil"

此约定是使您的Go包可供其他人使用的最简单方法。 Go Wikigodoc.org提供了外部Go项目的列表。

有关使用go工具使用远程存储库的更多信息,请参阅go help importpath