這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
https://golang.org/doc/code.html
Introduction(簡介)
本文包含了一個簡單的Go程式包和開發過程以及go tool的使用簡介。
go tool要求你的代碼有固定的組織形式。請認證閱讀此文,它將帶你如何如何最簡單的開始你的go編程之旅。
當然,我們還準備了一個直觀的視頻
Code Organization(程式碼群組織)
Workspaces
go tool 主要用於各種公用庫中的開原始碼。雖然你可能沒有打算髮布你的代碼,但是環境配置應該是一樣的。
go 代碼需要組織在一個workspace中,一個workpace值得是一個層級目錄結構,其根目錄中包含3個基本的子目錄
- src 包含Go原始碼檔案(以程式碼封裝來組織,一個程式碼封裝一個子目錄)
- pkg 包含包的目標檔案,類似其他語言中的編譯目標檔案
- bin 包含可執行檔
go tool 將會編譯原始碼包並將二進位檔案安裝至pkg目錄和bin目錄
src 子目錄包含並跟蹤來自於各種版本控制倉庫的原始碼
下面是一個workspace的實際例子:
bin/ hello # command executable outyet # command executablepkg/ linux_amd64/ github.com/golang/example/ stringutil.a # package objectsrc/ 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
該workspace包含一個程式碼程式庫(example),兩個最終命令列程式(hello和outyet)以及一個庫檔案(stringutil)。你可以直接參看github上的相關原始碼
一個典型的workspace將會包含多個程式碼封裝和多個可執行程式,大部分Go程式猿將他們的所有go代碼和依賴儲存在一個單獨的workspace中。
可執行程式和庫檔案將會從不同的原始碼包組織編譯,我們將在稍後討論。
The GOPATH environment variable
GOPATH 環境變數用來指明workspace的位置,這幾乎是你在開發Go程式過程中唯一需要設定的環境變數。
接下來,我們先建立一個workspace目錄,並為之設定環境變數GOPATH。你的workspace可以位於任何位置,此處我們使用$HOME/work。注意該目錄不能是Go的安裝目錄(另一個比較常見的設定是GOPATH=$HOME)
$ mkdir $HOME/work$ export GOPATH=$HOME/work
為了方便起見,可以將workspace的bin目錄添加到你的PATH目錄中
$ export PATH=$PATH:$GOPATH/bin
學習更多的關於GOPATH的用法,參閱go help gopath
Package paths
來自於標準庫的程式碼封裝都有類似“fmt”和“net/http”這樣簡短的路徑名。所以在你自己的程式碼封裝中,你需要盡量選擇一個不會和標準庫以及某些第三方庫命名衝突的基礎路徑名。
如果你將你的原始碼儲存在一個程式碼程式庫中,你應該使用程式碼程式庫的根目錄來作為你的基礎路徑名。比如你在GitHub上有這樣的一個路徑github.com/user,你應該使用它作為你程式碼封裝的基礎路徑。
注意一點,在你的代碼可以編譯通過之前,你並不需要將你在遠端倉庫中的代碼進行發布。如果你想要某一天去發布它,這樣組織代碼將會是一個很好的習慣。當然實際上你可以使用任意的路徑名,只要不和標準庫和一些常見第三方庫的命名衝突就可以。
接下來我們假設使用github.com/user作為我們的基礎路徑名,建立其在工作空間中對應的目錄結構:
$ mkdir -p $GOPATH/src/github.com/user
Your first program
接下來我們將要編譯並運行一個簡單的程式,首先選擇一個程式包路徑(這裡我們使用 github.com/user/hello)並在之前設定的workspace中建立對應目錄
$ mkdir $GOPATH/src/github.com/user/hello
下一步,在該目錄下建立一個hello.go的檔案,內容如下:
package mainimport "fmt"func main() { fmt.Printf("Hello, world.\n")}
下面我們可以使用go tool來編譯安裝該程式
$ go install github.com/user/hello
注意此命令可以在你的檔案系統中的任意位置運行,go tool將會通過GOPATH來在對應的workspace下尋找github.com/user/hello目錄。
如果你在程式包所在的目錄,你可以忽略路徑名來運行go install,如下所示:
$ cd $GOPATH/src/github.com/user/hello$ go install
go install命令編譯了hello代碼,產生了一個可執行檔,並將該可執行檔安裝至workspace目錄下的bin目錄中,命名為hello(在windows下是hello.exe)。在我們的樣本中,將是$GOPATH/bin/hello,即$HOME/work/bin/hello。
go tool只有在發生錯誤時才會產生輸出,所以如果這些命令執行過程中沒有輸出,以為著他們執行成功了。
接下來你可以運行剛才編譯安裝好的代碼:
$ $GOPATH/bin/helloHello, world.
如果你已經把$GOPATH/bin目錄添加到你的PATH目錄中,你可以直接按程式名調用它:
$ helloHello, world.
如果你使用了一個類似git的代碼控制系統,現在正是將其提交的好時機。當然,這些僅是可選的。
$ cd $GOPATH/src/github.com/user/hello$ git initInitialized 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
將代碼推倒遠端倉庫就作為讀者自己的聯絡吧,此處不再贅述。
Your first library
讓我們寫一個程式碼程式庫並在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
該命令並不會產生對應的可執行檔,只有go install命令才可以。在此例中他們都會在workspace的pkg目錄下產生對應的目標檔案。
確認了stringutil包已經正確編譯之後,修改 hello.go (在$GOPATH/src/github.com/user/hello目錄下)來使用我們剛剛寫好的方法。
$GOPATH/src/github.com/user/hello) to use it:package mainimport ( "fmt" "github.com/user/stringutil")func main() { fmt.Printf(stringutil.Reverse("!oG ,olleH"))}
無論go tool是用來編譯安裝一個可執行檔還是程式碼封裝,他都會編譯安裝其依賴的的內容,所以當你安裝hello程式時
$ go install github.com/user/hello
stringutil程式包會自動的編譯安裝完成
運行這個程式:
$ helloHello, Go!
經過以上幾步,你的workspace應該已經變成了這樣
bin/ hello # command executablepkg/ linux_amd64/ # this will reflect your OS and architecture github.com/user/ stringutil.a # package objectsrc/ github.com/user/ hello/ hello.go # command source stringutil/ reverse.go # package source
注意go install 命令將 stringutil.a目標檔案放置在了pkg/linux_amd64目錄下,這樣將來的引用可以直接在該目錄下找到該程式碼封裝從而防止重新編譯它。linux_amd64是為了協助於交叉編譯過程中,指明目標作業系統以及體繫結構。
Go的可執行檔採用靜態連結的形式,所以實際運行時不需要額外的目標檔案。
Package names
Go源檔案的第一句聲明必須是
package name
其中的name是程式碼封裝名(在同一程式碼封裝中的檔案都應該使用相同的name)
Go的傳統是程式碼封裝名應該使用匯入路徑的最後一個元素:比如匯入路徑名為crypto/rot13的包名應該為rot13。
可執行檔的包名始終需要是package main
對最終編譯到同一個檔案的所有相關依賴的包名並沒有唯一性的要求,只有完整的匯入路徑(包括包名)有唯一性要求
更多的Go命名傳統,請參閱Effective Go
Testing
Go內建一個輕量級的測試架構,由go test命令和testing包組成。
你可以建立一個尾碼為 _test.go的測試檔案,其中包含命名為TestXXX的類型為func (t *testing.T)的方法。該測試架構將會運行其中所有的此類方法。如果方法在運行中調用了類似t.Error和t.Fail的錯誤提示方法,意味著這個測試方法測試失敗。
下面給stringutil程式碼封裝增加一個測試函數$GOPATH/src/github.com/user/stringutil/reverse_test.go:
package stringutilimport "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/stringutilok github.com/user/stringutil 0.165s
與之前所說的一樣,如果你在程式碼封裝所在的目錄,你也可以直接運行如下
$ go testok github.com/user/stringutil 0.165s
運行go help test 以及參閱testing package documentation 來獲得關於測試架構的更多協助
Remote packages
匯入路徑會顯示從怎樣的版本控制系統(Git或者Mercurial等)能擷取對應的程式碼封裝。go tool利用這一點來自動從遠端倉庫那裡擷取對應的程式碼封裝。比如我們的範例程式碼都儲存在GitHub上github.com/golang/example。如果你在你的原始碼中使用這樣的匯入路徑,go get將能夠自動的擷取,編譯,安裝它:
$ go get github.com/golang/example/hello$ $GOPATH/bin/helloHello, Go examples!
如果當前的workspace中不包含匯入的程式包,go get命令將會把他放置在GOPATH的第一個路徑中(如果已經擷取,go get跳過擷取階段,就像運行go install一樣)
運行完以上的go get命令,我們的workspace應該已經看起來像這樣:
bin/ hello # command executablepkg/ linux_amd64/ github.com/golang/example/ stringutil.a # package object github.com/user/ stringutil.a # package objectsrc/ 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 Wiki 和 godoc.org 上列出了一些第三放Go代碼。
關於更多的使用go tool的遠端倉庫的方法,請參閱go help importpath
What’s next
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.
Getting help
For real-time help, ask the helpful gophers in #go-nuts on the Freenode IRC server.
The official mailing list for discussion of the Go language is Go Nuts.
Report bugs using the Go issue tracker.