golang 知識圖譜
https://www.processon.com/view/link/5a9ba4c8e4b0a9d22eb3bdf0
一、安裝
最新版本安裝包位址:https://golang.google.cn/dl/
要自己編譯安裝下載下傳 source 源碼包,否則根據自己 LINUX 系統下載下傳對應版本的編譯包,這裡直接下載下傳 go1.11.4.darwin-amd64.tar.gz
把下載下傳的 golang 包解壓到 /opt 下面:
sudo tar -C /opt/ -xzf go1.11.4.linux-amd64.tar.gz
解壓完 golang 語言包存在 /opt/go 下, 使用指令檢視go程式路徑 , 顯示 go 程式的路徑是 /opt/go/bin/go
whereis go
檢視 go 版本:
/opt/go/bin/go version
如果需要在 終端内直接 輸入 go 就能全局地使用 go 程式, 還需要配置系統環境變量。
在 /etc/profile 檔案後面加入配置:
export GOROOT=/opt/go
export GOPATH=/home/ecalf/goProject
export GOBIN=$GOPATH/bin
export PATH=$PATH:$GOBIN:$GOROOT/bin
或者建立下面軟體接
sudo ln -s /opt/go/bin/go /usr/bin/go
sudo ln -s /opt/go/bin/go /usr/local/bin/go
這些配置方法跟 node 的配置類似,有開發過 node 的經驗應該會很熟悉。
檢視 go 相關環境變量
go env
輸出
GOARCH="amd64"
GOBIN="/home/ecalf/goProject/bin"
GOCACHE="/home/ecalf/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/ecalf/goProject"
GOPROXY=""
GORACE=""
GOROOT="/opt/go"
GOTMPDIR=""
GOTOOLDIR="/opt/go/pkg/tool/linux_amd64"
GCCGO="/usr/bin/gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build111443368=/tmp/go-build -gno-record-gcc-switches"
GOROOT 是 go 所在目錄,go 指令在 GOROOT/bin 内;
GOPATH 是 go 的工作目錄,可以指定多個檔案夾。
$GOPATH 目錄約定有三個子目錄:
1. src 存放源代碼(比如:.go .c .h .s等)
2. pkg 編譯後生成的檔案(比如:.a)
3. bin 編譯後生成的可執行檔案(為了友善,把此目錄加入到 $PATH 變量中)
所有開發的 go 代碼都要放在 GOPATH/src 指定的目錄下,go get 等指令擷取的代碼包也會自動放置在這些目錄下。
環境變量配置好後,檢視go版本隻要在指令行輸入
go version
關于程式檔案編碼: Go語言的源檔案采用UTF8編碼。
二、hello world
在 $GOPATH/src 下建立項目檔案夾 hello,在 項目檔案夾下面編輯檔案: hello.go
package main
import "fmt"
/*first go program */
//hello world
func main() { //go 程式的新行不能以 { 開始
fmt.Println("Hello, World!")
}
進入$GOPATH/src/hello 目錄
使用 go run 指令直接在終端執行,檢視運作結果:
go run ./hello.go
使用 go build 指令把 go 程式編譯為可執行檔案
go build ./hello.go
使用 go install 指令編譯并生成可執行檔案
go install hello
指令執行後,在 $GOPATH/bin 下生成了可以行檔案 hello
在終端執行生成的程式
./hello
下面是幾個關于運作和編譯的指令:
go run: 編譯并直接運作程式,産生一個臨時檔案,直接在指令行輸出程式執行結果但不生成可執行檔案,多用于程式的簡單調試。當執行的檔案引用了包内其他檔案的方法時,必須指定編譯用到的所有檔案,這個時候可以使用通配符來指定編譯所有檔案 go run *.go 。 該指令執行的檔案可以放在任何目錄内,隻要正确指定要編譯的檔案路勁即可,但這些檔案必須是同一個 main 包内的。
go build:測試編譯包,主要檢查是否會有編譯錯誤,如果是一個可執行檔案的源碼(即是 main 包,go 的程式入口是 main 函數),就會在目前目錄下直接生成一個可執行檔案。
go install:該指令有2個作用,1.編譯程式,先編譯所有導入的封包件,然後才會編譯主程式;2.将編譯生成的可執行檔案放到 $GOPATH/bin 目錄下,編譯後的封包件放到 $GOPATH/pkg 目錄下。
其他 go 指令文檔可查閱下面官方文檔
https://golang.google.cn/cmd/
三、golang 的 package 概念
GO本身沒有項目的概念,隻有包,go 通過package來組織結構,每個 go 代碼檔案的第一行非注釋代碼都必須使用 package 指令來聲明代碼所屬的包名,同一個目錄中(不含子目錄)的所有代碼檔案隻能屬于同一個包,即一個檔案夾就是一個包。
go 的包分兩種:可執行包(指令包,有main函數,編譯後放在$GOPATH/bin内)和不可執行包(隻供調用,沒有main函數,編譯後放在$GOPATH/pkg内),包開發源代碼都放在 $GOPATH/src 目錄下,GO指令和編譯器會在 $GOROOT/src 和 $GOPATH/src 目錄下搜尋相應的包。
因為導入包的時候要通過封包件的目錄,而使用包提供的方法則需要通過包名,為了友善包定位,供調用的pkg包應該保持包名和目錄名稱一緻,有main函數的可執行包的包名必須是main,可以使用程式名稱作為包的檔案夾名稱。
可執行包的 main 函數:
- main 函數是go程式的入口, main 函數必須放在 package 名稱為 main 的包内。
- 一個可執行程式有且隻有一個main函數,同一個包内不能出現兩個main函數,否則 go build 指令和 go install 指令将報錯。
包的初始化:
- 一個包如果依賴另一個包,依賴包會被先導入和初始化。
- 包 可以定義 0個或多個 init 函數,包的 init 函數将在包被導入初始化後先于 main 函數自動執行。
- init 函數不需要傳入參數,也不會傳回任何值,不能被主動調用(如果被注定調用會提示init未聲明),重複導入包隻會執行一次 init 函數,init 函數可以調用其他函數。
- 如果一個包有多個init函數,他們的執行順序是不确定的。
包的導入:
- 如果導入了一個包但沒有使用它,編譯時将報錯。
- 如果你引用包隻是為了調用 init 函數去做一些初始化工作,但不打算使用包,可以将導入包重命名為 _ (空辨別符,也就是下劃線)來避免報錯。
- 當導入第三方包時,包名很可能非常接近或相同,需要使用别名來進行差別和調用。
- 如果導入的包被重命名為 . (點号),使用包的的方法時可以省略包名,但一般不建議這樣做。
- 包的可見性:定義的常量、變量、類型、接口、結構、函數等的名稱如果是小寫字母或下劃線開頭,表示是隻能在包内使用(有點像 protected),同一個包内,不同的檔案之間可以自由調用各檔案定義的常量、變量、函數,如果是大寫字母開頭則表示可以在包外被通路(有點像 public)。
導入 xxx/yyy 包并重名别名
import _ "xxx/yyy"
包的執行順序: 依賴包常量、變量、函數 初始化,指派 -> 依賴包 init函數 -> 包的初始化 ,指派 -> 包的init函數 -> main 函數
一個簡單的測試
src/bin/hello 包内有兩個檔案:
hello.go
package main
import "fmt"
import cat "../cat"
func main() {
fmt.Println("main function")
fmt.Println("Hello, World!")
sayHi();
wei();
cat.SayHello();//調用cat包的方法
}
func sayHi(){
fmt.Println("say hi")
}
func init(){
fmt.Println("init in hello")
}
wei.go
package main
import "fmt"
func init(){
fmt.Println("init in wei")
}
func wei(){
fmt.Println("wei...")
}
src/bin/cat 包内有一個檔案 cat.go :
package cat
import "fmt"
func init(){
fmt.Println("init in cat")
}
func miao(){
fmt.Println("miao miao ...")
}
func SayHello(){
miao()
}
進入 src/hello 下調試:
go run *.go
編譯生成可執行檔案
go install *.go
執行結果
init in cat
init in hello
init in wei
main function
Hello, World!
say hi
wei...
miao miao ...
to be continued