layout | title | date | categories | tags | comments | typora-root-url | excerpt |
---|---|---|---|---|---|---|---|
post |
How to Write Go Code 译文 |
2020-05-12 16:55:01 -0700 |
计算机 |
Go |
1 |
.. |
How to Write Go Code 译文 |
原文地址:https://golang.org/doc/code.html
更新时间:2020.05.12
未经许可不许转载,以免造成互联网冗余。
This document demonstrates the development of a simple Go package inside a module and introduces the go tool, the standard way to fetch, build, and install Go modules, packages, and commands.
本文档展示了一个简单 Go 包的开发,并介绍了用 go工具来获取、 构建并安装 Go 包及命令的标准方式。
Note: This document assumes that you are using Go 1.13 or later and the
GO111MODULE
environment variable is not set. If you are looking for the older, pre-modules version of this document, it is archived here.
注:该文档是假设你使用的是1.13或之后版本,以及GO111MODULE
环境变量没设定的情况下。如果你寻找更老的版本的文档,这里有存档。
Go programs are organized into packages. A package is a collection of source files in the same directory that are compiled together. Functions, types, variables, and constants defined in one source file are visible to all other source files within the same package.
Go程序装载于包(package)。一个包(package)是同一目录下若干源代码的集合体,将会一起被编译。函数、类型、变量、固定值将会被定义在同一个源代码文件,并且会公开于同一包下的其他源文件。
A repository contains one or more modules. A module is a collection of related Go packages that are released together. A Go repository typically contains only one module, located at the root of the repository. A file named
go.mod
there declares the module path: the import path prefix for all packages within the module. The module contains the packages in the directory containing itsgo.mod
file as well as subdirectories of that directory, up to the next subdirectory containing anothergo.mod
file (if any).
一个仓库包含了一或若干个模块,一个模块是若干个Go包的集合体,这些Go包将会同时被发布(released)。一个经典的Go仓库仅包含一个模块,该模块的位置是在仓库的根位置。在根路径处,一个名为go.mod
的文件,它里面声明了模块的路径——即,导入路径 将会成为这个模块里的所有包的前缀。该模块将会包含go.mod
所处的文件夹以及子文件夹中的包,如果该模块拥有子模块,那么该模块将遍历到含有另一个 go.mod
的文件夹位置(即遍历到下一个模块为止)。
Note that you don't need to publish your code to a remote repository before you can build it. A module can be defined locally without belonging to a repository. However, it's a good habit to organize your code as if you will publish it someday.
注:在你有能力构建代码之前,你不需要推送代码至远程仓库。模块可以在本地定义,而不需要(属于)仓库。然而,有意识地组织代码是一个好习惯,也许某天你需要推送代码(到仓库)。
Each module's path not only serves as an import path prefix for its packages, but also indicates where the
go
command should look to download it. For example, in order to download the modulegolang.org/x/tools
, thego
command would consult the repository indicated byhttps://golang.org/x/tools
(described more here).
每一个模块的路径不仅仅提供 它的包 路径前缀,而且还可以提示 go
命令去哪里下载(依赖包)。举例说明,如果你想要下载golang.org/x/tools
模块,那么 go
将通过https://golang.org/x/tools
该提示去查询仓库(详情请看here)。
An import path is a string used to import a package. A package's import path is its module path joined with its subdirectory within the module. For example, the module
github.com/google/go-cmp
contains a package in the directorycmp/
. That package's import path isgithub.com/google/go-cmp/cmp
. Packages in the standard library do not have a module path prefix.
一个导入路径是一个字符串,用于导入包。包的导入路径是它的模块路径 加上 该模块的子目录。举例说明, github.com/google/go-cmp
模块包含了一个名为cmp/
.的目录。那么该包的导入路径将会是github.com/google/go-cmp/cmp
。在标准库中的包是不需要模块前缀的。
To compile and run a simple program, first choose a module path (we'll use
example.com/user/hello
) and create ago.mod
file that declares it:
尝试编译并运行一个简单程序吧,首先选择一个模块路径(我们就用example.com/user/hello
吧),并创建一个go.mod
文件,并声明(定义)它。
$ mkdir hello # Alternatively, clone it if it already exists in version control.
$ cd hello
$ go mod init example.com/user/hello
go: creating new go.mod: module example.com/user/hello
$ cat go.mod
module example.com/user/hello
go 1.14
$
The first statement in a Go source file must be
package name
. Executable commands must always usepackage main
.
Go源代码的第一行语句必须是 package 名称
。可通过命令运行的可执行程序则(第一行)是 package main
。
Next, create a file named
hello.go
inside that directory containing the following Go code:
接下来,在文件夹内,创建一个名为 hello.go
的文件,内容如下:
package main
import "fmt"
func main() {
fmt.Println("Hello, world.")
}
Now you can build and install that program with the
go
tool:
现在,你可以通过 go
工具去构建并安装该程序
$ go install example.com/user/hello
$
This command builds the
hello
command, producing an executable binary. It then installs that binary as$HOME/go/bin/hello
(or, under Windows,%USERPROFILE%\go\bin\hello.exe
).
该命令将会构建一个hello
命令,并生成一个可执行的二进制文件。然后将它将该二进制文件安装成$HOME/go/bin/hello
, (在Windows环境下则是%USERPROFILE%\go\bin\hello.exe
).
The install directory is controlled by the
GOPATH
andGOBIN
environment variables. IfGOBIN
is set, binaries are installed to that directory. IfGOPATH
is set, binaries are installed to thebin
subdirectory of the first directory in theGOPATH
list. Otherwise, binaries are installed to thebin
subdirectory of the defaultGOPATH
($HOME/go
or%USERPROFILE%\go
).
安装地址由GOPATH
和 GOBIN
环境变量决定。如果GOBIN
设置了的话,则安装在这个目录下。如果GOPATH
设定了,则安装到第一个GOPATH
的bin
子目录下。否则,则安装在默认的GOPATH
($HOME/go
或 %USERPROFILE%\go
)的bin
子目录。
You can use the
go env
command to portably set the default value for an environment variable for futurego
commands:
你可以通过go env
命令便捷地设置默认环境量,设置后将会影响之后的go
命令:
$ go env -w GOBIN=/somewhere/else/bin
$
To unset a variable previously set by
go env -w
, usego env -u
:
删除(之前创建的)环境变量则使用go env -u
$ go env -u GOBIN
$
Commands like
go install
apply within the context of the module containing the current working directory. If the working directory is not within theexample.com/user/hello
module,go install
may fail.
像go install
的命令将会应用范围是,模块的所有内容,这包含当前工作目录。如果工作目录不包含example.com/user/hello
模块,那么go install
将会失败。
For convenience,
go
commands accept paths relative to the working directory, and default to the package in the current working directory if no other path is given. So in our working directory, the following commands are all equivalent:
为了方便,go
命令接受使用 工作目录的相对路径 ,以及当没有指定路径时,包的路径将会默认为当前工作目录。因此,在我们的工作目录,下面的命令是等价的:
$ go install example.com/user/hello
$ go install .
$ go install
Next, let's run the program to ensure it works. For added convenience, we'll add the install directory to our
PATH
to make running binaries easy:
接着,让我们运行程序,确认它能运行。为了更加方便,我们将安装目录添加到我们的PATH
里,使运行二进制文件更简单:
# 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.
$
If you're using a source control system, now would be a good time to initialize a repository, add the files, and commit your first change. Again, this step is optional: you do not need to use source control to write Go code.
如果你有在使用代码控制系统,那么现在是一个很好的机会去初始化仓库,添加这些文件,然后提交。这里再次强调,上述的操作是可选的,也许你并不需要使用 代码控制 去管理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
$
The
go
command locates the repository containing a given module path by requesting a corresponding HTTPS URL and reading metadata embedded in the HTML response (seego help importpath
). Many hosting services already provide that metadata for repositories containing Go code, so the easiest way to make your module available for others to use is usually to make its module path match the URL for the repository.
Go命令可以定位“内含给定模块地址的仓库”,定位原理是:通过发送一个对应的HTTPS地址,然后读取HTML response里的metadata内容 (详情看go help importpath
)。对于包含Go代码的仓库,许多托管服务(hosting service)已经提供用于这种仓库的元数据,因此最简单的方式让你的仓库有效化的方式是,让你的模块地址与仓库的URL相匹配。
Let's write a
morestrings
package and use it from thehello
program. First, create a directory for the package named$HOME/hello/morestrings
, and then a file namedreverse.go
in that directory with the following contents:
我们一起来写一个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)
}
Because our
ReverseRunes
function begins with an upper-case letter, it is exported, and can be used in other packages that import ourmorestrings
package.
因为ReverseRunes
函数的名字是大写开头,所以它将被暴露,也就是说,在其他包里导入morestrings
包后,我们可以使用这个函数。
Let's test that the package compiles with
go build
:
我们来试试用go build
来编译这个包
$ cd $HOME/hello/morestrings
$ go build
$
This won't produce an output file. Instead it saves the compiled package in the local build cache.
这个操作不会产生任何输出文件,取而代之的是,该操作会酱编译好的包放到“本地构建缓存”里。
After confirming that the
morestrings
package builds, let's use it from thehello
program. To do so, modify your original$HOME/hello/hello.go
to use the morestrings package:
在确认了morestrings
包成功构建后了,我们在hello
程序里用它吧。为了这样做,首先修改原来的文件$HOME/hello/hello.go
,去使用 morestrings 包
package main
import (
"fmt"
"example.com/user/hello/morestrings"
)
func main() {
fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
}
Install the
hello
program:
安装hello
程序
$ go install example.com/user/hello
Running the new version of the program, you should see a new, reversed message:
运行新版本程序,你可以看到一个新的、反转了的信息:
$ hello
Hello, Go!
An import path can describe how to obtain the package source code using a revision control system such as Git or Mercurial. The
go
tool uses this property to automatically fetch packages from remote repositories. For instance, to usegithub.com/google/go-cmp/cmp
in your program:
一个导入路径用于描述,怎么样通过Git或Mercurial等修订控制系统(Revision Control System),获得在包里的源代码。go
工具使用导入路径(该属性)去自动获取远程仓库的包。举例说明,如果你想要在程序中github.com/google/go-cmp/cmp
程序,就像下面代码:
package main
import (
"fmt"
"example.com/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"))
}
When you run commands like
go install
,go build
, orgo run
, thego
command will automatically download the remote module and record its version in yourgo.mod
file:
当运行类似go install
、go build
、 go run
这些命令时, go
命令将会自动下载远程模块,并将其版本记录至go.mod
中:
$ go install example.com/user/hello
go: finding module for package github.com/google/go-cmp/cmp
go: downloading github.com/google/go-cmp v0.4.0
go: found github.com/google/go-cmp/cmp in github.com/google/go-cmp v0.4.0
$ hello
Hello, Go!
string(
- "Hello World",
+ "Hello Go",
)
$ cat go.mod
module example.com/user/hello
go 1.14
require github.com/google/go-cmp v0.4.0
$
Module dependencies are automatically downloaded to the
pkg/mod
subdirectory of the directory indicated by theGOPATH
environment variable. The downloaded contents for a given version of a module are shared among all other modules thatrequire
that version, so thego
command marks those files and directories as read-only. To remove all downloaded modules, you can pass the-modcache
flag togo clean
:
模块的依赖被会自动下载到 GOPATH
环境变量的目录下的pkg/mod
的子目录里。下载的是模块指定版本的内容,其他模块可以共享该内容,但这些模块需要通过require
指定版本,因此go
命令把这些(下载了的)文件和目录都标记为只可读。(require
的示例可参考这里)
$ go clean -modcache
$
Go has a lightweight test framework composed of the
go test
command and thetesting
package.
Go有一个轻型的测试框架,由 go test
命令和testing
包组成。
You write a test by creating a file with a name ending in
_test.go
that contains functions namedTestXXX
with signaturefunc (t *testing.T)
. The test framework runs each such function; if the function calls a failure function such ast.Error
ort.Fail
, the test is considered to have failed.
测试文件名字后缀为_test.go
,文件包含名为 TestXXX
函数且签名(类型签名:Type signature)为 func (t *testing.T)
。该测试框架能运行上述的函数;当函数调用失败函数(如:t.Error
、 t.Fail
),测试结果会被认为失败。
Add a test to the
morestrings
package by creating the file$HOME/hello/morestrings/reverse_test.go
containing the following Go code.
在 morestrings
包里添加一个测试文件$HOME/hello/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)
}
}
}
Then run the test with
go test
:
运行go test
进行测试
$ go test
PASS
ok example.com/user/morestrings 0.165s
$
Run
go help test
and see the testing package documentation for more detail.
更多详情可运行 go help test
和查看testing package documentation
Subscribe to the golang-announce mailing list to be notified when a new stable version of Go is released.
See Effective Go for tips on writing clear, idiomatic Go code.
Take A Tour of Go to learn the language proper.
Visit the documentation page for a set of in-depth articles about the Go language and its libraries and tools.
For real-time help, ask the helpful gophers in the community-run gophers Slack server (grab an invite here).
The official mailing list for discussion of the Go language is Go Nuts.
Report bugs using the Go issue tracker.