How to Write Go Code
文章目录
Code Organization
- package: a collection of source files in the same directory that are compiled together
- module: a collection of related Go packages that are released together
go.mod
declares the module path: the import path prefix for all packages within the module- import path: a string used to import a package
First Program
$ 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
$
-
Go 的源文件中第一个 statement 必须是 package 的名字,一个可执行的文件必须使用
package main
-
创建
hello.go
package main
import "fmt"
func main() {
fmt.Println("Hello, world.")
}
- build and install
$ go install example.com/user/hello
$
-
二进制文件装在
$HOME/go/bin/hello
-
安装的目录由
GOPATH, GOBIN
来控制 -
假如
GOBIN
不为空,二进制文件会安装到GOBIN
指定的文件夹中 -
假如
GOPATH
不为空,二进制文件会安装到GOPATH
第一个路径下的bin
文件夹中 -
否则,默认安装在
$HOME/go
下面 -
可以使用
go env
来设置GOBIN
$ go env -w GOBIN=/somewhere/else/bin
$
- 解除设置
$ go env -u GOBIN
$
go install
作用在包含当前工作区的 module 上下文内,假如当前工作区不在 module 之内,go install
会失败go
可以接受相对路径,假如不给路径的话,默认是当前工作区下的包中进行,所以在适当的工作区中,以下三个命令是等效的:
$ go install example.com/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.
$
Importing packages from your module
- 写一个
morestrings
的包,首先创建$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
开头是大写字母,说明它是 exported ,可以用在其他的 package 里面- 用
go build
来编译一下:
$ cd $HOME/hello/morestrings
$ go build
$
- 没有输出,编译好的包会存在本地的编译缓存中
- 修改
$HOME/hello/hello.go
来使用这个morestrings
的包:
package main
import (
"fmt"
"example.com/user/hello/morestrings"
)
func main() {
fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
}
- 安装:
$ go install example.com/user/hello
- 执行:
$ hello
Hello, Go!
Importing packages from remote modules
- 可以
import
远程的 module
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"))
}
- 执行
go install
,go build
,go run
,go 会自动下载远程的 module 并将其版本信息记录在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 依赖会自动下载到
pkg/mod
文件夹下,可以通过go clean -modcache
来删除下载的 module
$ go clean -modcache
$
Testing
testing
,go test
- 测试文件以
_test.go
结尾,里面有一个函数TestXXX
,其签名为func(t *testing.T)
- 假如函数调用了
t.Error
或t.Fail
,说明测试失败 - 创建
$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)
}
}
}
- 进行测试:
$ go test
PASS
ok example.com/user/morestrings 0.165s
$