1. 安裝
1.1 本體軟件
在mac下,使用brew install go進行安裝。另外,我們知道從 Go 1.11 版本開始,官方支持了 go module 包依賴管理工具(參見 https://www.cnblogs.com/sage-blog/p/10640947.html),並新增了 GOPROXY 環境變量,下載源代碼時將會通過這個環境變量設置的代理地址,而不再是以前的直接從代碼庫下載。goproxy.io 這個開源項目幫我們實現好了我們想要的。該項目允許開發者一鍵構建自己的 GOPROXY 代理服務。同時,也提供了公用的代理服務 https://goproxy.io,我們只需設置該環境變量即可正常下載被牆的源碼包了:
# 啓用 Go Modules 功能
export GO111MODULE=on
# 配置 GOPROXY 環境變量
export GOPROXY=https://goproxy.io
1.2 與jupyter交互
參見 https://github.com/gopherdata/gophernotes,在mac下的安裝命令爲
env GO111MODULE=on go get github.com/gopherdata/gophernotes
mkdir -p ~/Library/Jupyter/kernels/gophernotes
cd ~/Library/Jupyter/kernels/gophernotes
cp "$(go env GOPATH)"/pkg/mod/github.com/gopherdata/[email protected]/kernel/* "."
chmod +w ./kernel.json # in case copied kernel.json has no write permission
sed "s|gophernotes|$(go env GOPATH)/bin/gophernotes|" < kernel.json.in > kernel.json
安裝好之後,打開jupyter notebook就能看到新增了go內核啦。
1.3 編程規範
和python一樣,Go是講究書寫格式的,函數的第一個{一定要和函數體在一起。有如下幾個包可以控制格式
- 使用gofmt -w命令標準化go文件
- 使用golint給出修改建議
- 使用godoc生成文檔
1.4 運行
使用go get安裝github上的包。-D表示僅下載不安裝。使用go install將src裏面的源文件安裝到$GOBIN文件夾下。
源文件使用go build編譯、go run運行。也可以直接go run XX.go運行,不要太方便。
2. 數據類型
2.1 基本類型
Go是靜態語言,數據類型包括:bool,string,int,float32,float64, [](數組)。Go中的變量聲明後,默認初始化爲“零值”。注意不像python,字符串不能用單引號。如果用反引號`,則不需要做轉義。
- 使用reflect包查看數據類型,reflect.TypeOf()
- 使用strconv包進行類型轉換,strconv.ParseBool(), strconv.FormatBool…
2.2 數組/切片/字典
- 數組,固定大小,一般不用:
var xx [2]string;xx := []int{1,2,3,4};xx := [6]int{1,2,3,4} - 切片,大小隻是個提示,可隨時新增:
var xx = make([]string,2)
xx = append(xx,value) - 數組和切片複製,使用:
copy(to, from) - 字典,使用make(map…),複雜數據結構都要用make關鍵字
xx := make(map[string] int)
用delete刪除數組元素:
detele(xx,key)
2.3 常量/變量,聲明/賦值,作用域
用const聲明常量。
定義變量的幾種方式:
var s string
var s string = "hello"
var s = "hello" // 類型推斷
s := "hello" // 類型推斷+去掉var的簡寫,只能在函數內使用。
使用塊表明作用域,用{}。文件本身是一個塊。外部塊可以訪問內部塊。
Go默認從package main的main函數進行。
2.4 結構體
定義:type xx struct{key1 string, key2 int}
使用:
m := xx{
key1: value1
key2: value2
}
或者
m:=xx{value1,value2}
結構體與後面的方法組合起來,可以模擬類。
3. 函數與接口
3.1 指針
和java大同小異:
- 使用 &變量 來獲得變量的指針
- 使用 *數據類型 來聲明指針類型
- 使用 *指針 來獲取指針對應的變量
3.2 函數
func XX(輸入 輸入格式) (輸出格式){
return 輸出
}
在輸入框中,可以用…表示任意數量的變量
在Go中,可以將函數名放到前面作爲變量:
XX:=func (輸入 輸入格式) (輸出格式){
return 輸出
}
即可以將 func (輸入 輸入格式) (輸出格式) 作爲一種數據類型進行傳輸,後面加一個()就可以執行一次這個函數變量,非常像java中的內聯函數。
3.3 方法
方法非常像函數,只是多了一個接收者。之所以這麼定義,是爲了模擬面向對象的類,使用type和方法就可以模擬類。
方法定義:func (m *Movie) summary(xx int) string{}
調用:m := Movie{…}; m.summary()
3.4 接口
接口定義:type XX interface{PowerOn() string},定義了接口名、需實現的方法等。
然後因爲函數並沒有implement關鍵字,所以實現接口的時候看不出來implement的是誰,最好加註釋說明。
4. 控制語句
- 條件語句:if x {} else {},可以繼續else if下去
- 循環語句1,經典for循環:for i:=0;i<10;i++{}
- 循環語句2,使用range,很像python中的enumerate:
numbers := []int{1,2,3,4}
for i,n := range numbers{
fmt.Println(n)
}
- 沒有while語句,用for代替
for {這裏面的語句會不停執行,要自己加停止條件}
- defer:函數執行完之後會執行defer語句,在關閉網絡連接、關閉文件等作業中很有用。
5. 讀寫/測試/日誌/異常/建站
- 讀寫文件:使用io/ioutil,讀出來是[]unit8,需轉換成需要的形式。注意緩存讀寫buffer.Bytes處理字符並直接使用string的+和append方法要快(可使用benchmark測試)。
- json:用encoding/json包處理json字段
- 正則表達式:regexp包
- 異常處理:使用errors,其接口定義:type error interface{Error() string}。fmt.Errorf對錯誤做格式化輸出
- 日誌:使用log,log.Printf、log.Fatal…。一般直接打印到標準輸出,然後在程序外處理。標準輸入0;標準輸出1;標準錯誤2
- 獲取命令行參數:使用range os.Args獲取所有參數;或者用flag.String(參數名,默認值,提示)定義,再使用flag.Parse()解析,使用*參數名獲取值。
- 測試:使用testing,參考這裏。幾個關鍵點:(1) 用xx_test.go命名測試文件;(2) 引入import “testing”;(3) 測試函數以Test開頭。有兩類測試,t表示單元測試,b表示基準測試。使用 -bench運行基準測試,使用-cover 報告覆蓋率。
- 建站:使用net/http包,下面是例子:
package main
import "net/http"
func hello(w http.ResponseWriter, r *http.Request){
w.Write([]byte("Hello world"))
}
func main(){
http.HandleFunc("/",hello)
http.ListenAndServe(":8000",nil)
}
6. 併發和通道
- 在函數前加一個go即可觸發併發,一般配合通道chan一起執行。通道定義方法:c:=make(chan string)。當通道作爲參數時:<-chan表明只讀,chan<-表明只寫,chan表明可讀寫
- 通道接收消息:c <- “hello”;接收通道數據:xx := <-c,這是一個阻塞操作
- 高級使用方法:用select case語句可以執行第一條達到的語句,執行後立即取消阻塞。使用time.After設置超時,格式爲:
//select基本用法
select {
case <- chan1:
// 如果chan1成功讀到數據,則進行該case處理語句
case chan2 <- 1:
// 如果成功向chan2寫入數據,則進行該case處理語句
case <-time.After(5*time.Second):
// 如果上面都沒有成功,則進入default處理流程。或者使用default執行默認操作
下面是例子
func showfunc(c chan string){
t := time.NewTicker(time.Second*2)
for {
c <- "function finished"
<-t.C
}
}
func main(){
c:=make(chan string)
stop:=make(chan bool)
go showfunc(c)
go func() {time.Sleep(time.Second*4);stop <- true}() //使用內聯函數
fmt.Println("start immediately")
for {
select{
case <-stop:
return
case msg := <-c:
fmt.Println(msg)
}
}
}
main()