## 概述
>[info] 目錄
* 介紹
* 代碼組織
* 概觀
* 工作區
* GOPATH環境變量
* 導入路徑
* 你的第一個程序
* 你的第一個庫
* 包名稱
* 測試
* 遠程軟件包
>[success] 介紹
本文檔演示了一個簡單Go包的開發過程,并介紹了go工具,這是獲取、構建和安裝Go包和命令的標準方法。
該go工具要求您以特定方式組織您的代碼。
>[success] ### 代碼組織
>[info] 概觀
請注意,這與其他編程環境不同,在這些編程環境中,每個項目都有一個單獨的工作區,工作區與版本控制存儲庫緊密相關。
* Go程序員通常將他們所有的Go代碼保存在一個工作區中。
* 工作區包含許多版本控制存儲庫 (例如,由Git管理)。
* 每個存儲庫都包含一個或多個包。
* 每個軟件包由一個目錄中的一個或多個Go源文件組成。
* 包的目錄的路徑決定了它的導入路徑。
>[success] 工作區
工作空間是一個目錄層次結構,其根目錄包含三個目錄:
* src 包含Go源文件,
* pkg 包含包對象
* bin 包含可執行命令。
該go工具構建源包并將生成的二進制文件安裝到pkg和bin目錄。
該src子目錄通常包含多個版本控制存儲庫(例如Git或Mercurial),用于跟蹤一個或多個源包的開發。
為了讓您了解工作空間在實踐中的外觀,下面是一個例子:
```golang
bin/
hello # 命令可執行文件
outyet # 命令可執行文件
pkg/
linux_amd64/
github.com/golang/example/
stringutil.a # 包對象
src/
github.com/golang/example/
.git/ # Git存儲庫元數據
hello/
hello.go # 命令源
outyet/
main.go # command source
main_test.go # test source
stringutil/
reverse.go # 包源碼
reverse_test.go # 測試源碼
golang.org/x/image/
.git/ # Git存儲庫元數據
bmp/
reader.go # package source
writer.go # package source
... (many more repositories and packages omitted) ...
```
上面的樹顯示了一個包含兩個存儲庫(example和image)的工作空間。該example庫包含兩個命令(hello 和outyet)和一個庫(stringutil)。該image存儲庫包含該bmp包和其他幾個包。
典型的工作空間包含許多包含許多包和命令的源代碼庫。大多數Go程序員將他們所有的Go源代碼和依賴關系保存在一個工作區中。
命令和庫由不同類型的源代碼包構建而成。
>[success] 第一個程序
要編譯并運行一個簡單的程序,首先選擇一個包路徑(我們將使用 github.com/user/hello)并在工作區內創建一個相應的包目錄:
```bash
mkdir $GOPATH/src/github.com/user/hello
```
接下來,創建一個名為hello.go該目錄內的文件,其中包含以下Go代碼。
```golang
package main
import "fmt"
func main() {
fmt.Printf("Hello, world.\n")
}
```
現在,您可以使用該go工具構建和安裝該程序
```golang
$ go install github.com/user/hello // 編譯包文件并且編譯整個程序
```
請注意,您可以從系統上的任何位置運行此命令。該 go工具通過查找 `github.com/user/hello ` 指定的工作區內的程序包來查找源代碼 `GOPATH`。
如果`go install`從軟件包目錄運行,也可以省略軟件包路徑:
```golang
$ cd $GOPATH/src/github.com/user/hello
$ go install
```
該命令構建`hello`命令,生成可執行的二進制文件。然后它將該二進制文件安裝到工作空間的`bin`目錄`hello`(或者在Windows下`hello.exe`)。在我們的例子中,那將是`$GOPATH/bin/hello`,這是`$HOME/go/bin/hello`。
該`go`工具只會在發生錯誤時打印輸出,因此如果這些命令不產生任何輸出,它們將成功執行。
您現在可以通過在命令行鍵入完整路徑來運行該程序:
```bash
$ $GOPATH/bin/hello
Hello, world.
```
或者,如您添加`$GOPATH/bin`到您的`PATH`,只需鍵入二進制名稱:
```golang
$ hello
Hello, world.
```
如果您正在使用源代碼管理系統,現在應該是初始化存儲庫,添加文件并提交第一個更改的好時機。再一次,這一步是可選的:你不需要使用源代碼控制來編寫Go代碼。
```bash
$ 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 commit
1 file changed, 1 insertion(+)
create mode 100644 hello.go
$ git remote add origin https://github.com/Tinywan/hello.git
$ git push -u origin master
```
將代碼推送到遠程存儲庫作為自己的練習。
>[success] 你的第一庫
我們來編寫一個庫并從`hello`程序中使用它。
再次,第一步是選擇一個包路徑(我們將使用 `github.com/user/stringutil`)并創建包目錄:
```bash
$ mkdir $GOPATH/src/github.com/user/stringutil
```
接下來,``使用以下內容創建一個名稱在該目錄中的文件。
```golang
// 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`命令進行代碼編譯:、
```bash
$ go build github.com/user/stringutil // 測試編譯,檢查編譯是否有編譯錯誤
```
或者,如果您在包的源目錄中工作,只需:
```bash
$ go build
```
這不會產生輸出文件。為此,必須使用`go install`將包對象放置在工作空間的`pkg`目錄中的方法。
確認stringutil軟件包構建完成后,修改原始文件`hello.go`(位于 `$GOPATH/src/github.com/user/hello`)以使用它:
```golang
package main
import (
"fmt"
"github.com/user/stringutil"
)
func main() {
fmt.Printf(stringutil.Reverse("!oG ,olleH"))
}
```
無論何時該go工具**安裝包或二進制文件**,**它也會安裝它所具有的任何依賴關系**。所以當你安裝hello程序
```bash
$ go install github.com/user/hello
```
該`stringutil`包也將自動安裝。
運行該程序的新版本,您應該看到一條新的反轉消息:
```bash
$ hello
Hello, Go!
```
完成上述步驟后,您的工作空間應如下所示:
```bash
bin/
hello # command executable
pkg/
linux_amd64/ # this will reflect your OS and architecture
github.com/user/
stringutil.a # package object
src/
github.com/user/
hello/
hello.go # command source
stringutil/
reverse.go # package source
```
請注意,`go install`將`stringutil.a`對象放置在`pkg/linux_amd64`鏡像源目錄中的目錄中。這樣未來的`go`工具調用可以找到包對象并避免不必要地重新編譯包。該`linux_amd64`部分有助于交叉編譯,并將反映您的系統的操作系統和體系結構。
**Go命令可執行文件是靜態鏈接的**,包對象不需要存在來運行Go程序。
>[success] 包名稱
Go源文件中的第一條語句必須是
```bash
package name
```
這里`name`是對進口的包的默認名稱。(包中的所有文件都必須使用相同的文件`name`)
Go的慣例是包名稱是導入路徑的最后一個元素:`crypto/rot13`應該命名導入為“ ” 的包rot13。
可執行命令必須始終使用`package main`。
沒有要求軟件包名稱在鏈接到一個二進制文件的所有軟件包中唯一,**只需要導入路徑(它們的完整文件名)是唯一的**。
請參閱[Effective Go](http://127.0.0.1:8080/doc/effective_go.html#names)詳細了解Go的命名約定。
>[success] 測試
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`包含以下Go代碼的文件 向測試包 添加測試。
```golang
package stringutil
import "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`:
```bash
$ go test github.com/user/stringutil
ok github.com/user/stringutil 0.165s
```
與往常一樣,如果您正在go從軟件包目錄運行該工具,則可以省略軟件包路徑:
```bash
$ go test
ok github.com/user/stringutil 0.165s
```
運行`go help test`并查看 測試包文檔以獲取更多詳細信息。
>[success] 遠程軟件包
導入路徑可以描述如何使用Git或Mercurial等版本控制系統獲取軟件包源代碼。該go工具使用此屬性從遠程存儲庫自動獲取軟件包。例如,本文檔中描述的示例也保存在GitHub托管的Git存儲庫中` github.com/golang/example`。如果您在存儲庫的導入路徑中包含存儲庫URL,` go get`將自動獲取,構建和安裝它:
```bash
$ go get github.com/golang/example/hello
$ $GOPATH/bin/hello
Hello, Go examples!
```
如果指定的軟件包不在工作區中,`go get `則將其放入由指定的第一個工作區內`GOPATH`。(如果包已經存在,則go get跳過遠程抓取并且行為與go install。)相同。)
發出上述`go get`命令后,工作空間目錄樹現在應該如下所示:
```golang
bin/
hello # command executable
pkg/
linux_amd64/
github.com/golang/example/
stringutil.a # package object
github.com/user/
stringutil.a # package object
src/
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
```
hello在GitHub上托管的命令取決于`stringutil`同一個存儲庫中的軟件包。在導入`hello.go`文件中使用相同的導入路徑約定,所以` go get`命令能夠找到并安裝相關的包了。
導入`“github.com/golang/example/stringutil”`這個約定是讓你的Go軟件包可供其他人使用的最簡單的方法。在轉到維基 和`godoc.org` 提供外部圍棋項目清單。
有關在go工具中使用遠程存儲庫的更多信息,請參閱 go help importpath。