[TOC]
[https://github.com/golang](https://github.com/golang)
手冊
[https://cloud.tencent.com/developer/section/1142075](https://cloud.tencent.com/developer/section/1142075)
下載地址
[http://mirrors.ustc.edu.cn/golang/](http://mirrors.ustc.edu.cn/golang/)
# 優勢
* 可以直接編譯成機器碼,不依賴其他庫,glibc的版本有一定要求,部署就是扔一個文件上去
* 跨平臺編譯,如果你寫的代碼不包含cgo,那么就可以做到windows系統編譯linux的應用.go引用了plan9的代碼,這就是不依賴系統的信息
* 內嵌c支持,Go里面也可以直接包含c代碼,利用現有的豐富c庫
自動搜索所有函數并集中到一個.a文件
生成library時候是會自動把`$GOPATH/src/github.com/cyent/golang/example/stringutil/`下面所有.go文件里包含的函數集中到`stringutil.a`中(根據這些.go文件中的package xxx來自動加入到一個.a),因此如果存在相同的函數,會報錯提示重復
# 學習資料
go語言官網: https://golang.org/
go中文社區: https://studygolang.com/
go中文在線文檔: https://studygolang.com/pkgdoc
# 命令源碼文件
如果一個源碼文件聲明屬于main包,并且包含一個無參數聲明且無結果聲明的main函數,那么它就是命令源碼文件
~~~
package main
import "fmt"
func main() {
fmt.Println("Hello, world!")
}
~~~
# 命令行
* 編譯go代碼,生成一個可執行程序
~~~
go build xxx.go
~~~
然后這個程序就可以執行了
* 不生成可執行文件,直接運行
~~~
go run xxx.go
~~~
* `go install`
配置GOPATH到src同級的絕對目錄`src/xx`
需要配置GOBIN
到src目錄執行go install就行,會生成2個目錄在src同級
自動生成pkg和bin
pkg放平臺,bin放可執行程序
# 環境變量
* `src`存放源代碼(比如:.go .c .h .s等)? ?按照golang默認約定,go run,go install等命令的當前工作路徑(即在此路徑下執行上述命令)。
* `pkg`編譯時生成的中間文件(比如:.a) golang編譯包時
* `bin`編譯后生成的可執行文件(為了方便,可以把此目錄加入到 $PATH 變量中,如果有多個gopath,那么使用`${GOPATH//://bin:}/bin`添加所有的bin目錄)
代碼目錄結構: GOPATH下的src目錄就是接下來開發程序的主要目錄,所有的源碼都是放在這個目錄下面,那么一般我們的做法就是一個目錄一個項目,
例如: $GOPATH/src/mymath 表示mymath這個應用包或者可執行應用,這個根據package是main還是其他來決定,main的話就是可執行應用,其他的話就是應用包,這個會在后續詳細介紹package
`go install/go get`和 go的工具等會用到GOPATH環境變量
goroot在上面
~~~
export GOPATH=/Users/hopkings/www/Go
export GOBIN=$GOPATH/bin
export PATH=$PATH:$GOBIN
~~~
**go get**
會做兩件事:
1. 從遠程下載需要用到的包
2. 執行go install
`go get = git clone + go install` 從指定源上面下載或者更新指定的代碼和依賴,并對他們進行編譯和安裝
**go install**
go install 會生成可執行文件直接放到bin目錄下,當然這是有前提的
你編譯的是可執行文件,如果是一個普通的包,會被編譯生成到pkg目錄下該文件是.a結尾
# go build
1. 運行go build命令時加入標記-x,這樣可以看到go build命令具體都執行了哪些操作。另外也可以加入-n,只查看具體操作不執行他們
2. 運行go build命令加入標記-v,這樣可以看到go build命令編譯源碼包的名稱,和-a標記搭配很有用
3. 執行該命令而且不加參數,會試圖把當前目錄作為代碼包編譯. `-a`所有涉及到代碼包都被編譯,不加只會編譯歸檔文件而不是最新的代碼包
# go get
從github下載后安裝到GOPATH第一個工作區的相應目錄中.如果存在GOBIN,那么僅包含命令元am文件代碼會裝到GOBIN那
-u: 下載并安裝代碼包,不論是否存在
-d: 只下載不安裝
-fix: 下載代碼包后先運行一個用于根據當前go版本修正代碼的工具,然后再安裝代碼包
-t: **同時下載測試所需的代碼包**
-insecure: 允許通過非安全的網絡協議下載,比如http
**uses insecure protocol**
~~~
export url=''
export project=''
git config --global url."git@${url}:".insteadOf "http://${url}/" go get -v -insecure "${url}${project}"
~~~
# go env

# 查看編譯的依賴
mac上沒有ldd和strace
mac對應的是otool和strace,需要root
查看動態鏈接庫`otool -L`
~~~
ldd 可執行文件
~~~

上圖中的三列數據分別代表:
1. 第一列:程序依賴的庫
2. 第二列:系統提供的對應庫
3. 第三列:庫加載的開始地址
通過對比第一列和第二列數據,可以分析程序依賴的庫和系統實際提供的庫,看兩者是否相匹配。
通過第三列數據,可以知道在當前的庫中的符號在對應的進程的地址空間中的開始位置
# 交叉編譯

有效的`$GOOS`和`$GOARCH`組合如下
~~~
$GOOS $GOARCH
android arm
darwin 386
darwin amd64
darwin arm
darwin arm64
dragonfly amd64
freebsd 386
freebsd amd64
freebsd arm
linux 386
linux amd64
linux arm
linux arm64
linux ppc64
linux ppc64le
linux mips
linux mipsle
linux mips64
linux mips64le
netbsd 386
netbsd amd64
netbsd arm
openbsd 386
openbsd amd64
openbsd arm
plan9 386
plan9 amd64
solaris amd64
windows 386
windows amd64
~~~
交叉編譯主要是兩個編譯環境參數 `$GOOS` 和 `$GOARCH` 的設定
`$GOOS`代表編譯的目標系統,`$GOARCH`代表編譯的處理器體系結構
`$GOOS`可選值如下
~~~
darwin
dragonfly
freebsd
linux
netbsd
openbsd
plan9
solaris
windows
~~~
`$GOARCH`可選值如下
~~~
386
amd64
arm
~~~
Mac 下編譯 Linux 和 Windows 64位可執行程序
~~~
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go
~~~
在Linux系統下跨平臺編譯
~~~shell
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build xxx.go
~~~
在Windows系統下跨平臺編譯
~~~shell
set CGO_ENABLED=0
set GOARCH=386
set GOOS=windows
go build xxx.go
~~~
選擇性編譯
雖然golang 可以跨平臺編譯,但卻無法解決系統的差異性。總在一些時候我們會直接調用操作系統函數。相同功能編寫類似xxx_windows.go xxx.Linux.go文件,根據操作系統編譯對應源文件。而不是在文件中用if else規劃執行路徑。 要實現選擇性編譯需要在文件頂部增加構建標記。
~~~
// +build
~~~
此標記必須出現在文件頂部,僅由空行或其他注釋行開頭。也就是必須在Package 語句前。此標記后接約束參數,格式為 // +build A,B !C,D 逗號為且,空格為或,!為非。代表編譯此文件需符合 (A且B) 或 ((非C)且D) 。A和C的可選參數可參見本文上面的 $GOOS參數,B和D的可選參數可參見$GOARCH 。比如
~~~
// +build !windows,386
//此文件在非windows操作系統 且386處理器時編譯
~~~
最后, Golang為跨系統運行的確是已經做得夠好了。沒有C C++的歷史包袱,但充分吸取了他們的諸多特點,為加快工作效率損失的軟件性能是值得的
# 編譯器
在網絡上的諸多教程中可能會看到下面的編譯命令
~~~
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build hello.go
~~~
其中CGO\_ENABLED=0的意思是使用C語言版本的GO編譯器,參數配置為0的時候就關閉C語言版本的編譯器了。自從golang1.5以后go就使用go語言編譯器進行編譯了。在golang1.9當中沒有使用CGO\_ENABLED參數發現依然可以正常編譯。當然使用了也可以正常編譯。比如把CGO\_ENABLED參數設置成1,即在編譯的過程當中使用CGO編譯器,我發現依然是可以正常編譯的。
實際上如果在go當中使用了C的庫,比如`import "C"`默認使用go build的時候就會啟動CGO編譯器,當然我們可以使用CGO\_ENABLED=0來控制go build是否使用CGO編譯器。
# GOPROXY
~~~
export GOPROXY=https://goproxy.io
~~~
or
~~~
$env:GOPROXY = "https://goproxy.io"
~~~

# 壓縮可執行文件
首先加上編譯參數`-ldflags`
`-s`相當于strip掉符號表, 但是以后就沒辦法在gdb里查看行號和文件了。 `-w` 告知連接器放棄所有debug信息
~~~
$ go build -ldflags '-w -s'
~~~
使用upx壓縮,Linux、Mac和Win都有,這里以Mac為例
upx就是對可執行文件進行壓縮,然后可以已極快的速度解壓并運行
~~~
$ brew install upx
$ upx etcd-cli
~~~
Golang開發的程序都會比較大,這是因為Golang是靜態編譯的,編譯打包之后基本就不會再對其他類庫有依賴了,所以會比較大。舉個例子:C++程序可以調用dll,所以打包的時候可以不把dll打進去,包自然就小了。之前還有看到過有人使用`GO -> C -- dll --> C -> GO`的方式間接實現了Golang的偽動態鏈接
# go cache
通過運行`go env GOCACHE`命令來查看緩存目錄的路徑。緩存的數據總是能夠正確地反映出當時的各種源碼文件、構建環境、編譯器選項等等的真實情況。
一旦有任何變動,緩存數據就會失效,go 命令就會再次真正地執行操作。所以我們并不用擔心打印出的緩存數據不是實時的結果。go 命令會定期地刪除最近未使用的緩存數據,但是,如果你想手動刪除所有的緩存數據,運行一下`go clean -cache`命令就好了
# goland調試
菜單依次選擇“Run”->“Edit configurations”如下圖所示:


- 基礎
- 簡介
- 主要特征
- 變量和常量
- 編碼轉換
- 數組
- byte與rune
- big
- sort接口
- 和mysql類型對應
- 函數
- 閉包
- 工作區
- 復合類型
- 指針
- 切片
- map
- 結構體
- sync.Map
- 隨機數
- 面向對象
- 匿名組合
- 方法
- 接口
- 權限
- 類型查詢
- 異常處理
- error
- panic
- recover
- 自定義錯誤
- 字符串處理
- 正則表達式
- json
- 文件操作
- os
- 文件讀寫
- 目錄
- bufio
- ioutil
- gob
- 棧幀的內存布局
- shell
- 時間處理
- time詳情
- time使用
- new和make的區別
- container
- list
- heap
- ring
- 測試
- 單元測試
- Mock依賴
- delve
- 命令
- TestMain
- path和filepath包
- log日志
- 反射
- 詳解
- plugin包
- 信號
- goto
- 協程
- 簡介
- 創建
- 協程退出
- runtime
- channel
- select
- 死鎖
- 互斥鎖
- 讀寫鎖
- 條件變量
- 嵌套
- 計算單個協程占用內存
- 執行規則
- 原子操作
- WaitGroup
- 定時器
- 對象池
- sync.once
- 網絡編程
- 分層模型
- socket
- tcp
- udp
- 服務端
- 客戶端
- 并發服務器
- Http
- 簡介
- http服務器
- http客戶端
- 爬蟲
- 平滑重啟
- context
- httptest
- 優雅中止
- web服務平滑重啟
- beego
- 安裝
- 路由器
- orm
- 單表增刪改查
- 多級表
- orm使用
- 高級查詢
- 關系查詢
- SQL查詢
- 元數據二次定義
- 控制器
- 參數解析
- 過濾器
- 數據輸出
- 表單數據驗證
- 錯誤處理
- 日志
- 模塊
- cache
- task
- 調試模塊
- config
- 部署
- 一些包
- gjson
- goredis
- collection
- sjson
- redigo
- aliyunoss
- 密碼
- 對稱加密
- 非對稱加密
- 單向散列函數
- 消息認證
- 數字簽名
- mysql優化
- 常見錯誤
- go run的錯誤
- 新手常見錯誤
- 中級錯誤
- 高級錯誤
- 常用工具
- 協程-泄露
- go env
- gometalinter代碼檢查
- go build
- go clean
- go test
- 包管理器
- go mod
- gopm
- go fmt
- pprof
- 提高編譯
- go get
- 代理
- 其他的知識
- go內存對齊
- 細節總結
- nginx路由匹配
- 一些博客
- redis為什么快
- cpu高速緩存
- 常用命令
- Go 永久阻塞的方法
- 常用技巧
- 密碼加密解密
- for 循環迭代變量
- 備注
- 垃圾回收
- 協程和纖程
- tar-gz
- 紅包算法
- 解決golang.org/x 下載失敗
- 逃逸分析
- docker
- 鏡像
- 容器
- 數據卷
- 網絡管理
- 網絡模式
- dockerfile
- docker-composer
- 微服務
- protoBuf
- GRPC
- tls
- consul
- micro
- crontab
- shell調用
- gorhill/cronexpr
- raft
- go操作etcd
- mongodb