非常重要的兩個地址
介紹
本文檔演示了在模塊內開發一個簡單的 Go 包,並介紹了 go tool:這是獲取、構建和安裝 Go 模塊、包和命令的標准方法。
注意: 本文假定你使用的是Go 1.13或更高版本的Go,並且GO111MODULE環境變量沒有設置。如果你要找這個文檔的舊版本、前模塊的版本,here.。
代碼組織形式
Go程序被組織成包。一個包是同一目錄下的源文件的集合,這些源文件被編譯在一起。在一個源文件中定義的函數、類型、變量和常量對同一包內的所有其他源文件都是可見的。
一個存儲庫包含一個或多個模塊。一個模塊是由一起發布的相關的Go包組成的集合。一個 Go 倉庫通常只包含一個模塊,位於倉庫的根目錄下。
一個名為go.mod的文件在那里聲明了模塊路徑:模塊內所有包的導入路徑前綴。該模塊包含了包含go.mod文件的目錄中的包,以及該目錄的子目錄,直到下一個包含go.mod文件的子目錄(如果有的話)。
注意,你不需要先把代碼發布到遠程倉庫中,然后才構建它。一個模塊可以在本地定義,而不屬於一個版本庫。然而,像這樣組織你的代碼是一個好習慣,就像你有一天會發布代碼一樣。
每個模塊的路徑不僅可以作為它的包的導入路徑前綴,還可以指示go命令應該在哪里下載它。例如,為了下載golang.org/x/tools模塊,go命令將查詢https://golang.org/x/tools(這里有更多描述here)。
導入路徑是一個用於導入包的字符串。一個包的導入路徑是指它的模塊路徑和模塊內的子目錄。例如,模塊github.com/google/go-cmp目錄中包含了一個包,在cmp/目錄下。這個包的導入路徑是github.com/google/go-cmp/cmp。標准庫中的包沒有模塊路徑前綴。
你的第一個程序
要編譯和運行一個簡單的程序,首先選擇一個模塊路徑(我們將使用 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 $
Go源文件中的第一個語句必須是package name。可執行的命令必須始終使用package main。
接下來,在該目錄下創建一個名為hello.go的文件,包含以下Go代碼。
package main import "fmt" func main() { fmt.Println("Hello, world.") }
現在你可以用go工具建立並安裝該程序。
$ go install example.com/user/hello $
這個命令建立hello命令,生成一個可執行的二進制文件。然后,它將這個二進制文件安裝到 $HOME/go/bin/hello (或者在 Windows 下,%USERPROFILE%go\bin\hello.exe)。
安裝目錄由GOPATH和GOBIN環境變量控制。如果設置了GOBIN,二進制文件就會被安裝到這個目錄下。如果設置了GOPATH,二進制文件將被安裝到GOPATH列表中第一個目錄的bin子目錄。否則,二進制文件會被安裝到默認的GOPATH目錄下的bin子目錄($HOME/go或%USERPROFILE/go)。
你可以使用 go env 命令來為未來的 go 命令設置環境變量的默認值。
$ go env -w GOBIN=/somewhere/else/bin
$
要取消之前通過go env -w設置的變量,請使用go env -u。
$ go env -u GOBIN
$
像go install這樣的命令適用於包含當前工作目錄的模塊的上下文。如果工作目錄不在 example.com/user/hello 模塊中,go 安裝可能會失敗。
為了方便起見,go命令接受相對於工作目錄的路徑,如果沒有給出其他路徑,則默認為當前工作目錄下的包。所以在我們的工作目錄下,以下命令都是等價的。
$ go install example.com/user/hello $ go install . $ go install
接下來,讓我們來運行程序,確保它能正常運行。為方便起見,我們將把安裝目錄添加到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. $
如果你使用的是源碼控制系統,現在是初始化倉庫,添加文件,並提交第一次修改的好時機。同樣,這一步是可選的:如果你不使用源碼控制來編寫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 URL和讀取HTML響應中的元數據來定位包含給定模塊路徑的存儲庫(參見go help importpath)。許多托管服務已經為包含Go代碼的資源庫提供了元數據,因此,要讓你的模塊供他人使用,最簡單的方法就是讓它的模塊路徑與資源庫的URL匹配。
從你的模塊中導入包
讓我們寫一個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函數是以大寫字母開頭的,所以它是exported的,可以在其他import我們morestrings包的包中使用。
讓我們用go build來測試一下這個包的編譯。
$ cd $HOME/hello/morestrings
$ go build
$
這不會產生一個輸出文件。相反,它將編譯后的包保存在本地構建緩存中。
在確認了morestrings包的構建后,讓我們在hello程序中使用它。為此,修改你原來的 $HOME/hello/hello/hello.go 來使用 morestrings 包。
package main import ( "fmt" "example.com/user/hello/morestrings" ) func main() { fmt.Println(morestrings.ReverseRunes("!oG ,olleH")) }
安裝hello程序。
$ go install example.com/user/hello
運行新版本的程序,你應該會看到一條新的、相反的消息。
$ hello
Hello, Go!
從遠程模塊導入包
一個導入路徑可以描述如何使用版本控制系統(如Git或Mercurial)獲取包的源代碼。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")) }
當你運行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 $
模塊的依賴關系會自動下載到GOPATH環境變量指示的目錄下的pkg/mod子目錄。給定版本的模塊的下載內容會在所有需要該版本的模塊中共享,所以go命令將這些文件和目錄標記為只讀。要刪除所有下載的模塊,你可以通過 -modcache 標志來清除。
$ go clean -modcache
$
測試
Go有一個由go test命令和testing包組成的輕量級測試框架。
你通過創建一個以_test.go命名的文件來編寫一個測試,該文件包含一個名為TestXXX的函數,簽名為func(t *testing.T)。測試框架會運行每個這樣的函數;如果函數調用了失敗函數,如t.Error或t.Fail,則認為測試失敗。
通過創建文件$HOME/hello/morestrings/reverse_test.go,在morestrings包中添加一個測試,其中包含以下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運行測試。
$ go test
Passed
OK example.com/user/morestrings 0.165s
$
運行 go help test
,查看測試包文檔了解更多細節 testing package documentation.
接下來
訂閱 golang-announce 郵件列表,當 Go 的新穩定版本發布時,你會收到通知。
請參閱 Effective Go ,了解如何寫出清晰、流暢的 Go 代碼。
也可以從入門教程開始:https://tour.golang.org/ 還有中文版 https://tour.go-zh.org/。
訪問documentation page,了解有關go語言及其庫和工具的深度文章。
https://golang.google.cn/doc/install