go

語言簡介

go是強類型靜態語言,也就是說在編譯階段就肯定變量類型,而且轉換類型須要顯示轉換,它有以下幾個特色:
  1. 跟腳本語言類似,容易上手、容易流行
  2. 底層是c,性能好
  3. 對goroutine調度進行了封裝,即在語言層面支持協程,對於開發者,用起來方便

編譯過程

  • go以包的形式管理源程序,每一個包至少包含一個go文件。編譯的時候會把main包生成可執行文件放到bin目錄下,其餘包生成xx.a包文件放到pkg目錄下。

可執行程序初始化過程

  • 先執行main包的go文件,對依賴的包遞歸執行import、常量和變量初始化、init函數流程以後,初始化main本身的常量和變量、再依次執行init函數和main函數,示意圖以下(居然不能直接放圖片,😳):
    https://github.com/JJAWX/imag...

go文件基本構成

package xx

代表這個go文件是屬於哪一個包,這條語句是必須寫的,由於go是以package的形式管理源文件的

import xx

引入當前文件依賴的包,包的路徑只能夠是相對路徑,eg:"xxx/decorator",go查找包的過程是先在$GOROOT/src($GOROOT是go的安裝路徑,默認在/usr/local/go下)文件夾下找,若是找不到就從$GOPATH/src($GOPATH是go工做空間路徑,當前工做代碼所在的go文件夾路徑)文件下找。

var/const聲明初始化

整型
var test int = 123
布爾
var test bool = true
字符串
var test string = "abc"
數組(數組必須指定長度,不然屬於切片,不賦值,指定長度默認[0,0])
var test [2]int
    test[0] = 6
    test[1] = 8
切片(沒指定長度的數組或者用make初始化的數組)
// 添加元素方式一
    var test = make([]string, 0)
    test = append(test, 2)
    // 添加元素方式二
    var test = make([]string, 2)
    test[0] = "123"
    test[1] = "456"
結構體
type TestA struct {
        c int
    }
    type Test struct {
        a int
        b string
        c int
        TestA
    }
    var test = Test{6, "aa", 8, TestA{3}} // 或者不初始化:var test Test
channel
test := make(chan int)
    go func(){ test <- 1 }()
    fmt.Printf("aaa: %+v", <-test)
interface{}(一個接口能夠擁有任何實現了它全部方法的類型的屬性,空接口表明全部對象都實現了它,也就是說用它能夠接收任何類型)
type Test interface{
        Say()
    }
    type TestA struct{}
    func (a TestA) Say(){
        fmt.Printf("hello")

    } 
    var testa TestA
    var test Test
    test = testa // 接口類型,
指針
var  testPtr *int // 定義了沒有分配到任何變量時,爲空指針
map(默認是nil,不初始化,不能存任何東西)
// 方式一
    var test = make(map[string]string)
    test["a"] = "123"
    
    // 方式二
    var test = map[string]string{}
    test["a"] = "123"
    
    // 方式三
    test := make(map[string]string)
    test["a"] = "123"

init函數

初始化一些全局變量,供所屬包或者全部包調用git

main函數

屬於main包,是程序的入口,和main包是一一對應的關係。github

其餘函數

業務子邏輯,處理客戶端的GET、POST、PUT、DELETE等請求,get請求使用url庫對請求參數進行解析,跟它相關的幾個方法是:DefaultQuery、Query、QueryArray,;GET、POST、PUT、DELETE請求的話使用的是gin框架的model binding模型,相關的幾個方法是:BindWith、BindJSON、Bind、它們底層都使用了MustBindWith這個方法, 這個方法接收兩個參數,一個是要解析的struct(ps:解析的對象必須是struct或者是指向struct的指針),另外一個是binding,由跟Bind相關的幾個函數指定,指定的方式區別以下:json

  • BindWith: 可接收兩個參數,一個是要解析的對象,一個是binding
  • BindJSON: 只接收一個參數,是要解析的對象,使用的binding是bing.JSON,它對要解析的數據是怎麼處理的呢,從req.body中拿出要解析的數據,使用reflect反射對要解析的對象類型進行判斷,而後從req.body中取要的數據
  • Bind: 接收一個參數,會根據請求的method和content-type判斷使用什麼binding來解決。

邏輯處理完成,須要使用context.JSON(關鍵:json.Marshal)或context.HTML(ps: 分別接收三個參數:狀態碼、模版路徑、模版數據)將結果返回給客戶端。數組

go異常捕捉處理

和異常處理相關的幾個關鍵字:defer(return的時候執行)、recover(捕捉異常)、panic(err)(拋出異常),須要注意的地方是若是子協程不捕捉處理異常,就會報到主線程,由主線程處理,可是子協程會異常退出。緩存

func example () {
        defer func() {
            if err := recover(); err != nil {
                fmt.Printf("error: %+v", err)
            } else {
                fmt.Printf("拋出了一個nil")
            }
        }()
        // panic(nil) // 結果:拋出了一個nil
        panic("fail") // 結果: error: failed
    }

go併發

go關鍵字 + channel

// 無緩衝通道
    func example () {
        test := make(chan int)
        go func(){
            test <- 1
        }()
        fmt.Printf("channel value: %+v", <-test)
    }
    // 執行結果
    channel value: 1
    
    // 緩衝通道
    func example () {
        test := make(chan int, 2)
        go func(){
            for i := 0; i < 2; i++ {
                test <- i
            }
            close(test) // 很重要,須要手動關閉,要否則會形成死鎖
        }()
        for ch := range test {
            fmt.Printf("channel value: %+v", ch)
            fmt.Println("")
        }
    }
    // 執行結果
    channel value: 0
    channel value: 1

sync.WaitGroup(例子 + 結果)

func example () {
        var wg sync.WaitGroup
        for i := 0; i < 2; i++ {
            m := i // 考慮到主線程釋放控制權以後協程才執行,緩存i
            wg.Add(1)
            go func(){
                defer func(){
                    fmt.Println("ending...")
                    wg.Done()
                }()
                fmt.Println(fmt.Sprintf("當前循環到哪裏了: %+v", m))
            }()
        }
        
        fmt.Println("example...")
        wg.Wait()
    }
    // 執行結果
    example...
    當前循環到哪裏了: 0
    ending...
    當前循環到哪裏了: 1
    ending...
相關文章
相關標籤/搜索