如何编写Go代码
簡(jiǎn)介
本文演示了一個(gè)簡(jiǎn)單的Go語(yǔ)言包的開(kāi)發(fā),以及 go tool 命令的使用,包含:獲取、構(gòu)建、安裝Go包和命令的標(biāo)準(zhǔn)方法。
go tool 要求用特別的方式來(lái)組織你的Go代碼。仔細(xì)閱讀本文,它解釋了啟動(dòng)和運(yùn)行Go安裝的最簡(jiǎn)單方法。
代碼組織
概述
- 程序員通常會(huì)將所有Go代碼保存在一個(gè)工作區(qū)中
- 工作空間包含許多版本控制的倉(cāng)庫(kù)(repo)(例如,由Git管理的)
- 每個(gè)倉(cāng)庫(kù)包含一個(gè)或多個(gè)包
- 每個(gè)包由一個(gè)目錄中的一個(gè)或多個(gè)Go源文件組成
- 包目錄的路徑確定其導(dǎo)入路徑
請(qǐng)注意,這與其他編程環(huán)境不同,在這些環(huán)境中,每個(gè)項(xiàng)目都有一個(gè)單獨(dú)的工作區(qū),工作區(qū)與版本控制倉(cāng)庫(kù)緊密相關(guān)。
工作區(qū)
工作空間是一個(gè)目錄層次結(jié)構(gòu),其根目錄有兩個(gè)目錄:
- src 用于存放Go原文件
- bin 存放可執(zhí)行的命令
go工具構(gòu)建二進(jìn)制文件并將其安裝到 bin 目錄。
src 子目錄通常包含多個(gè)版本控制的倉(cāng)庫(kù)(例如Git),用于跟蹤一個(gè)或多個(gè)源包的開(kāi)發(fā)。
在實(shí)踐中,工作區(qū)應(yīng)該是什么樣子呢? 下面給出一個(gè)例子:
bin/hello # command executableoutyet # command executable src/github.com/golang/example/.git/ # Git repository metadatahello/hello.go # command sourceoutyet/main.go # command sourcemain_test.go # test sourcestringutil/reverse.go # package sourcereverse_test.go # test sourcegolang.org/x/image/.git/ # Git repository metadatabmp/reader.go # package sourcewriter.go # package source... (many more repositories and packages omitted) ...上面的這個(gè)樹(shù)型結(jié)構(gòu)展示出一個(gè)工作區(qū)包含了2個(gè)倉(cāng)庫(kù)(example 和 image)。example 倉(cāng)庫(kù)包含了2個(gè)命令(hello 和 outyet)和一個(gè)庫(kù)(stringutil)。image 倉(cāng)庫(kù)包含了 bmp 包和 一些其他的包。
通常工作區(qū)會(huì)包含很多的源倉(cāng)庫(kù)(包含需要多和命令)。大多數(shù)的Go開(kāi)發(fā)者都會(huì)把他們的源代碼和依賴存放在一個(gè)工作區(qū)。
命令和庫(kù)是從不同類型的源包構(gòu)建的。我們稍后會(huì)討論這種區(qū)別。
GOPATH 環(huán)境變量
GOPATH 環(huán)境變量用來(lái)指定工作區(qū)的位置。默認(rèn)是用戶主目錄的 go 目錄,如在Linux和macOS上是 $HOME/go, 在Windows上是 C:\Users\YourName\go。
go env GOPATH 命令會(huì)打印出當(dāng)前有效的 GOPATH; 如果環(huán)境變量沒(méi)有被設(shè)置會(huì)打印出默認(rèn)的位置。
為方便起見(jiàn),將工作空間的 bin 子目錄添加到 PATH:
$ export PATH=$PATH:$(go env GOPATH)/bin為簡(jiǎn)潔起見(jiàn),本文檔其余部分中的腳本使用 $GOPATH 而不是 $(go env GOPATH)。即
$ export PATH=$PATH:$GOPATH/bin而如果還沒(méi)有設(shè)置 $GOPATH 就運(yùn)行寫(xiě)好的腳本,你需要替換為 $HOME/go, 否則需要執(zhí)行:
$ export GOPATH=$(go env GOPATH)要學(xué)習(xí)更多關(guān)于gopath環(huán)境變量,可以使用查看幫助 go help gopath
要使用自定義的工作區(qū),可以查看 https://golang.org/wiki/SettingGOPATH
導(dǎo)入路徑
導(dǎo)入路徑(import path)是唯一標(biāo)識(shí)包的字符串。包的導(dǎo)入路徑對(duì)應(yīng)于其在工作空間內(nèi)或遠(yuǎn)程倉(cāng)庫(kù)中的位置(如下所述)。
標(biāo)準(zhǔn)庫(kù)中的包具有簡(jiǎn)短的導(dǎo)入路徑,例如 fmt 和 net/http。對(duì)于我們自己開(kāi)發(fā)的包您必須選擇一個(gè)基本路徑,該路徑不太可能與將來(lái)添加到標(biāo)準(zhǔn)庫(kù)或其他外部庫(kù)中發(fā)生沖突。
如果將代碼保存在某個(gè)源倉(cāng)庫(kù)中,則應(yīng)使用該源倉(cāng)庫(kù)的根作為基本路徑。例如,如果你在 github.com/user 上有一個(gè)GitHub帳戶,那么這應(yīng)該是你的基本路徑。
請(qǐng)注意,在構(gòu)建代碼之前,無(wú)需將代碼發(fā)布到遠(yuǎn)程倉(cāng)庫(kù)。組織代碼只是一個(gè)好習(xí)慣,好像有一天你會(huì)發(fā)布它一樣。實(shí)際上,你可以選擇任意路徑名稱,只要它對(duì)標(biāo)準(zhǔn)庫(kù)和更大的Go生態(tài)系統(tǒng)是唯一的。
我們將使用 github.com/user 作為我們的基本路徑。在工作區(qū)內(nèi)創(chuàng)建一個(gè)目錄,用于保存源代碼:
$ mkdir -p $GOPATH/src/github.com/user你的第一個(gè)Go程序
要編譯和運(yùn)行一個(gè)簡(jiǎn)單的程序,首先要選擇一個(gè)包路徑(我們會(huì)使用 github.com/user/hello),然后在工作區(qū)里創(chuàng)建一個(gè)相應(yīng)的包目錄:
$ mkdir $GOPATH/src/github.com/user/hello接下來(lái),在hello目錄里創(chuàng)建一個(gè) hello.go 文件,寫(xiě)入以下內(nèi)容:
package mainimport "fmt"func main() {fmt.Println("Hello, world.") }現(xiàn)在就可以使用go工具來(lái)構(gòu)建和安裝該程序:
go install github.com/user/hello注意,你可以在系統(tǒng)上的任何地方運(yùn)行該命令。go工具通過(guò)在 GOPATH 指定的工作空間內(nèi)查找 github.com/user/hello 包來(lái)查找源代碼。
如果是在這個(gè)包目錄內(nèi)運(yùn)行 go install 也可以忽略包路徑:
$ cd $GOPATH/src/github.com/user/hello $ go install該命令會(huì)生成一個(gè) hello 命令,生成一個(gè)可執(zhí)行的二進(jìn)制文件。同時(shí)安裝到工作區(qū)目錄下的 bin 目錄,生成的可執(zhí)行文件是 hello(如果是windows則是 hello.exe)。
在本例子中是 $GOPATH/bin/hello, 也就是 $HOME/go/bin/hello。
當(dāng)有錯(cuò)誤發(fā)生的時(shí)候,go工具僅會(huì)打印除錯(cuò)誤,所以如果沒(méi)有任何輸出的時(shí)候說(shuō)明已經(jīng)執(zhí)行成功。
可以通過(guò)全路徑來(lái)運(yùn)行:
$ $GOPATH/bin/hello Hello, world.如果已經(jīng)把 $GOPATH/bin 加入到了 PATH, 可以直接輸入二進(jìn)制文件名:
$ hello Hello, world.如果你正在使用一個(gè)版本控制系統(tǒng),比如Git,現(xiàn)在是時(shí)候來(lái)初始化來(lái)生成一個(gè)倉(cāng)庫(kù)(repository),然后添加文件,做第一次提交。
當(dāng)然這一步是可選的,不一定非要使用版本控制系統(tǒng)來(lái)寫(xiě)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 commit1 file changed, 1 insertion(+)create mode 100644 hello.go $ git push origin master你的第一個(gè)庫(kù)
我們?cè)賮?lái)寫(xiě)一個(gè)庫(kù),并在 hello 程序中使用。
首先,第一步確定好包路徑,我們使用 github.com/user/stringutil, 創(chuàng)建包目錄
$ mkdir $GOPATH/src/github.com/user/stringutil其次,創(chuàng)建一個(gè)名為 reverse.go 的文件,并寫(xiě)入以下內(nèi)容:
// 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如果已經(jīng)在 github.com/user/stringutil 目錄里,則直接執(zhí)行:
$ go build當(dāng)然該命令不會(huì)生成文件,而是把編譯好的包放到了本地的構(gòu)建(build)緩存里。
確實(shí) stringutil 包被編譯后, 修改 hello.go:
修改后的:
package mainimport ("fmt""github.com/user/stringutil" )func main() {fmt.Println(stringutil.Reverse("!oG ,olleH")) }再次安裝
$ go install github.com/user/hello執(zhí)行:
$ hello Hello, Go!通過(guò)上面的一些步驟后,現(xiàn)在我們的結(jié)構(gòu)是這樣子的:
bin/hello # command executable src/github.com/user/hello/hello.go # command sourcestringutil/reverse.go # package source包名
在Go原文件中第一個(gè)使用的語(yǔ)句必須是
package name其中 name 就是包的默認(rèn)名稱。一個(gè)包中的所有文件必須使用相同的包名。
Go的約定是包名稱是導(dǎo)入路徑的最后一個(gè)元素,例如導(dǎo)入的包 crypto/rot13, 包名就是 rot13
如果是可執(zhí)行的文件,包名必須使用 main。
不強(qiáng)制要求所有的包名都是唯一的,但是要求導(dǎo)入的路徑必須是唯一的(全路徑文件名)。
更多關(guān)于go的命名規(guī)范可以查看 Effective Go
測(cè)試
Go提供了一個(gè)由 go test 和 testing 包組成的測(cè)試框架。
通過(guò)創(chuàng)建一個(gè)以 _test.go 結(jié)尾的文件,里面寫(xiě)有以 TestXXX 開(kāi)頭的函數(shù)。測(cè)試框架會(huì)運(yùn)行每一個(gè)這樣的函數(shù),如果函數(shù)調(diào)用了一個(gè)失敗的函數(shù),如 t.Error 或 t.Error, 那么測(cè)試就算不通過(guò)。
通過(guò)添加一個(gè)測(cè)試文件到 stringutil 包中,
$ vim $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)}} }然后運(yùn)行測(cè)試 go test:
$ go test github.com/user/stringutil ok github.com/user/stringutil 0.165s如果當(dāng)前是在 go test github.com/user/stringutil 目錄中,則直接執(zhí)行:
$ go test ok github.com/user/stringutil 0.165s更多細(xì)節(jié)可以運(yùn)行 go run test 和 查看 測(cè)試包文檔
遠(yuǎn)程包
導(dǎo)入路徑可以描述如何使用諸如Git之類的版本控制系統(tǒng)來(lái)獲取包源代碼。go工具使用此屬性自動(dòng)從遠(yuǎn)程倉(cāng)庫(kù)獲取包。例如,本文檔中描述的示例也保存在GitHub github.com/golang/example 上托管的Git倉(cāng)庫(kù)中。如果你在包的導(dǎo)入路徑中包含倉(cāng)庫(kù)URL,那么go將自動(dòng)獲取,構(gòu)建和安裝它:
$ go get github.com/golang/example/hello $ $GOPATH/bin/hello Hello, Go examples!如果指定的包不在工作區(qū), go get 將會(huì)通過(guò) GOPATH 把它放到指定的工作區(qū),如果包已經(jīng)存在, go get 會(huì)跳過(guò)遠(yuǎn)程獲取,其行為與 go install 相同。
上面 go get 之后的目錄結(jié)構(gòu)如下:
bin/hello # command executable src/github.com/golang/example/.git/ # Git repository metadatahello/hello.go # command sourcestringutil/reverse.go # package sourcereverse_test.go # test sourcegithub.com/user/hello/hello.go # command sourcestringutil/reverse.go # package sourcereverse_test.go # test source在GitHub上托管的 hello 命令取決于同一倉(cāng)庫(kù)中的 stringutil 包。 hello.go 文件中的導(dǎo)入使用相同的導(dǎo)入路徑約定,因此 go get 命令也能夠找到并安裝依賴包。
import "github.com/golang/example/stringutil"此約定是使你的Go包可供其他人使用的最簡(jiǎn)單方法。
Go Wiki和godoc.org提供了外部Go項(xiàng)目的列表。
有關(guān)使用go工具使用遠(yuǎn)程倉(cāng)庫(kù)的更多信息, 可以查看 go help importpath
原文地址:https://phpcasts.org/topics/47總結(jié)
- 上一篇: JS(JavaScript)的初了解6(
- 下一篇: spring coud feign