go語言精要

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是講究書寫格式的,函數的第一個{一定要和函數體在一起。有如下幾個包可以控制格式

  1. 使用gofmt -w命令標準化go文件
  2. 使用golint給出修改建議
  3. 使用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 數組/切片/字典

  1. 數組,固定大小,一般不用:
    var xx [2]string;xx := []int{1,2,3,4};xx := [6]int{1,2,3,4}
  2. 切片,大小隻是個提示,可隨時新增:
    var xx = make([]string,2)
    xx = append(xx,value)
  3. 數組和切片複製,使用:
    copy(to, from)
  4. 字典,使用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大同小異:

  1. 使用 &變量 來獲得變量的指針
  2. 使用 *數據類型 來聲明指針類型
  3. 使用 *指針 來獲取指針對應的變量

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. 控制語句

  1. 條件語句:if x {} else {},可以繼續else if下去
  2. 循環語句1,經典for循環:for i:=0;i<10;i++{}
  3. 循環語句2,使用range,很像python中的enumerate:
numbers := []int{1,2,3,4}
for i,n := range numbers{
    fmt.Println(n)
}
  1. 沒有while語句,用for代替
for {這裏面的語句會不停執行,要自己加停止條件}
  1. defer:函數執行完之後會執行defer語句,在關閉網絡連接、關閉文件等作業中很有用。

5. 讀寫/測試/日誌/異常/建站

  1. 讀寫文件:使用io/ioutil,讀出來是[]unit8,需轉換成需要的形式。注意緩存讀寫buffer.Bytes處理字符並直接使用string的+和append方法要快(可使用benchmark測試)。
  2. json:用encoding/json包處理json字段
  3. 正則表達式:regexp包
  4. 異常處理:使用errors,其接口定義:type error interface{Error() string}。fmt.Errorf對錯誤做格式化輸出
  5. 日誌:使用log,log.Printf、log.Fatal…。一般直接打印到標準輸出,然後在程序外處理。標準輸入0;標準輸出1;標準錯誤2
  6. 獲取命令行參數:使用range os.Args獲取所有參數;或者用flag.String(參數名,默認值,提示)定義,再使用flag.Parse()解析,使用*參數名獲取值。
  7. 測試:使用testing,參考這裏。幾個關鍵點:(1) 用xx_test.go命名測試文件;(2) 引入import “testing”;(3) 測試函數以Test開頭。有兩類測試,t表示單元測試,b表示基準測試。使用 -bench運行基準測試,使用-cover 報告覆蓋率。
  8. 建站:使用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()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章