golang常用標準庫


輸入與輸出-fmt包

輸入與輸出

  • 常用輸出函數

    Print、Printf、Println:直接輸出內容

    Sprint、Sprintf、Sprintln:生成內容并返回字符串

    Fprint:將內容輸出到一個io.Writer接口類型的變量,經常用于寫入文件

    Errorf:根據format參數生成格式化字符串并返回一個包含該字符串的錯誤

```go
fmt.Println("打開文件出錯,err:", err)//輸出帶換行
s2 := fmt.Sprintf("name:%s,age:%d", name, age)//帶格式生成并返回
fmt.Fprintf(fileObj, "往文件中寫如信息:%s", name)//帶格式寫入文件
err := fmt.Errorf("這是一個錯誤")
```
  • 常用占位符

    占位符 說明
    %v 值的默認格式表示
    %+v 類似%v,但輸出結構體時會添加字段名
    %#v 值的golang語法表示
    %T 打印值的類型
    %% 百分號
    %d 表示10進制數
    %b 表示2進制數
    %f 浮點數,有小數
    %9.2f 寬度9,精度2
    %e 科學計數法
    %s 直接輸出字符串或[]byte
    %q 該值對應的雙引號括起來的go語法字符串字面值,必要時會采用安全的轉義表示
    %p 指針,表示未16進制,并加上前綴0x
  • 常用輸入函數

    Scan、Scanf、Scanln:可以在程序運行過程中從標準輸入獲取用戶的輸入。

    Scanln比較常用:在終端掃描標準輸入,以空格分隔,直到換行結束掃描

```go
fmt.Scanln(&name, &age, &married)
fmt.Printf("掃描結果 name:%s age:%d married:%t \n", name, age, married)
```

bufio.NewReader:獲取完整輸入內容

FScan、Fscanf、Fscanln:從文件中獲取輸入

Sscan、Sscanf、Sscanln:從字符串獲取輸入

時間與日期-time包

  • 時間與日期轉換

    func timeDemo() {
        now := time.Now() //獲取當前時間
        fmt.Printf("current time:%v\n", now)
    
        year := now.Year()     //年
        month := now.Month()   //月
        day := now.Day()       //日
        hour := now.Hour()     //小時
        minute := now.Minute() //分鐘
        second := now.Second() //秒
        fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second)
    
        timestamp1 := now.Unix()     //時間戳
        timestamp2 := now.UnixNano() //納秒時間戳
        fmt.Printf("current timestamp1:%v\n", timestamp1)
        fmt.Printf("current timestamp2:%v\n", timestamp2)   
        
        timeObj := time.Unix(timestamp1, 0)//時間戳轉換成時間對象,再通過類似以上當前時間轉換成時間格式
    
    }
    
  • 時間間隔(單位)

    time包中時間間隔的定義:

    const (
        Nanosecond  Duration = 1
        Microsecond          = 1000 * Nanosecond
        Millisecond          = 1000 * Microsecond
        Second               = 1000 * Millisecond
        Minute               = 60 * Second
        Hour                 = 60 * Minute
    )
    
    var _time = 10 * time.Second //10秒
    

    例如:time.Duration表示1納秒,time.Second表示1秒。

  • 時間格式化

    golang的常用時間格式化模板并不是常見的:Y-m-d H:i:s,而是2006-01-02 15:04 ,這是24小時制,2006-01-02 03:04 PM,則是12小時制

    fmt.Println(now.Format("2006-01-02 15:04:05.000 Mon Jan"))
    // 12小時制
    fmt.Println(now.Format("2006-01-02 03:04:05.000 PM Mon Jan"))
    fmt.Println(now.Format("2006/01/02 15:04"))
    fmt.Println(now.Format("15:04 2006/01/02"))
    fmt.Println(now.Format("2006/01/02"))
    

    golang大佬,何必呢,增加跨語言語法記憶難度,雖然只是一點點,但如果其他地方也這樣有'意思',累計下難度就不小了。

  • 時間操作

    golang中的時間,并不是簡單的數字加減,time包提供了實踐操作的方法:

    • Add:時刻+時間段

      func main() {
          now := time.Now()
          later := now.Add(time.Hour) // 當前時間加1小時后的時間
          beforer := now.Add(-time.Hour) // 當前時間減1小時后的時間
          fmt.Println(later)
      }
      
    • Sub:時刻1 - 時刻2,求兩個時間的差值,注意這里并不是(時刻-時間段)的實現,(時刻-時間段)仍然可以用Add(-時間段)來實現

    • Equal:判斷時間是否相等,會考慮時區

    • Before:判斷是否在某個時刻之前

    • After:判斷是否在某個時刻之后

  • 定時器

    定時器,本質上是一個channel,golang中使用time.Ticker(duration)來設置定時器

    • 一次性定時器(延時)

      package main
      
      import (
          "fmt"
          "time"
      )
      
      func main() {
          /*
              用sleep實現定時器
          */
          fmt.Println(time.Now())
          time.Sleep(time.Second)
          fmt.Println(time.Now())
          /*
              用timer實現定時器
          */
          timer := time.NewTimer(time.Second)
          fmt.Println(<-timer.C)
          /*
              用after實現定時器
          */
          fmt.Println(<-time.After(time.Second))
      
      }
      
    • 周期性定時器

      func tickDemo() {
          ticker := time.Tick(time.Second) //定義一個1秒間隔的定時器
          //ticker := time.NewTicker(time.Second)
          for i := range ticker {
              fmt.Println(i)//每秒都會執行的任務
          }
      }
      

命令行參數解析-flag包

flag包是的golang開發命令行工具更為簡單。

看一個完整示例,我們就更清楚flag的用途了:

執行命令時要求輸入4個參數,并指定了參數的類型與默認值

func main() {
    //定義命令行參數方式1
    var name string
    var age int
    var married bool
    var delay time.Duration
    flag.StringVar(&name, "name", "張三", "姓名")
    flag.IntVar(&age, "age", 18, "年齡")
    flag.BoolVar(&married, "married", false, "婚否")
    flag.DurationVar(&delay, "d", 0, "延遲的時間間隔")

    //解析命令行參數
    flag.Parse()
    fmt.Println(name, age, married, delay)
    //返回命令行參數后的其他參數
    fmt.Println(flag.Args())
    //返回命令行參數后的其他參數個數
    fmt.Println(flag.NArg())
    //返回使用的命令行參數個數
    fmt.Println(flag.NFlag())
}

首先flag提供了命令行help功能,執行命令行會給出相應提示:

    $ ./flag_demo -help
    Usage of ./flag_demo:
      -age int
            年齡 (default 18)
      -d duration
            時間間隔
      -married
            婚否
      -name string
            姓名 (default "張三")

其次flag提供命令行參數parse解析能力:

注意:Args()\NArg()\NFlag()的含義

$ ./flag_demo -name pprof --age 28 -married=false -d=1h30m
pprof 28 false 1h30m0s
[]
0
4

當然如果我們僅僅只是需要簡單命令行輸入的參數,我們也可以簡單的考慮os.Args來獲取命令行參數。

os.Args是一個存儲命令行參數的字符串切片,它的第一個元素是執行文件的名稱,這和大部分語言命令行模式是類似的(python、php等)

日志-log包

官方標準簡單log包,功能有限,更多可以實現流水賬的日志記錄,如果我們需要更多比如不同級別的日志記錄,可以選擇第三方日志庫:logrus、zap等

//使用標準日志log,設置日志輸出到xx.log文件,設置flags支持文件名、行號、日志前綴、時間格式
func main() {
    logFile, err := os.OpenFile("./xx.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
    if err != nil {
        fmt.Println("open log file failed, err:", err)
        return
    }
    log.SetOutput(logFile)
    log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate)    
    log.SetPrefix("[JM]")
    log.Println("這里記錄一條日志。")
}
[JM]2020/01/14 15:32:45.431506 .../log_demo/main.go:13: 這里記錄一條日志。

IO操作-os包

os包提供了Create、NewFile、Open、OpenFile、Remove方法

返回的文件對象,提供了讀寫方法,比如Write、WriteAt、WriteString、Read、ReadAt方法

  • 文件打開與關閉

    package main
    
    import (
        "fmt"
        "os"
    )
    
    func main() {
        // 只讀方式打開當前目錄下的main.go文件
        file, err := os.Open("./main.go")
        if err != nil {
            fmt.Println("open file failed!, err:", err)
            return
        }
        // 關閉文件
        file.Close()
    }
    

    golang可以考慮再簡化下文件的打開及異常的處理和關閉,python的with open簡化了try異常和close的處理,讓代碼更簡潔,編寫者不用去關心異常處理和文件關閉處理代碼,這本不屬于業務邏輯代碼,趨勢應該是讓語言或機器自動實現了

  • 寫文件
```go
file.WriteString("ab\n")
file.Write([]byte("cd\n"))
```

我們會更新一篇關于byte與string區別的文章
  • 讀文件

    golang文件讀取可以用file.Read()和file.ReadAt(),讀到文件末尾會返回io.EOF的錯誤,EOF這是大部分語言讀取結尾的標識符了

    golang的os包的讀寫還需要偏上層封裝,不要讓開發者去了解這么多讀寫的原理,比如讀取一行、整個文件,這些是開發者更樂意用到的,不用關心讀寫的原理,至于性能開發者會認為是語言要解決的問題,當然當我們有足夠經驗以后,就可以使用更底層些的方法來實現,提高性能。如果硬件的發展更快,我們更希望大家都可以不關心底層實現的去使用更上層的方法

    package main
    
    import (
        "fmt"
        "io"
        "os"
    )
    
    func main() {
        // 打開文件
        file, err := os.Open("./xxx.txt")
        if err != nil {
            fmt.Println("open file err :", err)
            return
        }
        defer file.Close()
        // 定義接收文件讀取的字節數組
        var buf [128]byte
        var content []byte
        for {
            n, err := file.Read(buf[:])
            if err == io.EOF {
                // 讀取結束
                break
            }
            if err != nil {
                fmt.Println("read file err ", err)
                return
            }
            content = append(content, buf[:n]...)
        }
        fmt.Println(string(content))
    }
    

IO操作-bufio包與ioutil包

bufio包實現了帶緩沖區的讀寫,是對文件讀寫的封裝

前面說到開發者更喜歡使用更上層的讀寫方法,golang的bufio包除了實現帶緩沖區的讀寫提高效率和穩定性外,還提供按行讀方法,ioutil包提供了讀取整個文件、寫文件方法

bufio、ioutil包更多文件、目錄讀寫詳見官方標準庫

strconv包

  • Atoi

    string類型轉換成int類型

  • Itoa

    int轉換成string

  • ParaseType系列

    將string轉換成指定Type類型

    b, err := strconv.ParseBool("true")
    f, err := strconv.ParseFloat("3.1415", 64)
    i, err := strconv.ParseInt("-2", 10, 64)
    u, err := strconv.ParseUint("2", 10, 64)
    
  • FormatType系列

    將給定類型數據格式化為string類型數據的功能

    s1 := strconv.FormatBool(true)
    s2 := strconv.FormatFloat(3.1415, 'E', -1, 64)
    s3 := strconv.FormatInt(-2, 16)
    s4 := strconv.FormatUint(2, 16)
    

strconv包中還有Append系列、Quote系列等函數。詳細見官方標準庫

模板-template包

html/template包實現了數據驅動的模板,用于生成可對抗代碼注入的安全HTML輸出。

  • 模板語法

    {{.}}
    

    模板語法都包含在{{和}}中間,其中{{.}}中的點表示當前對象。

    當我們傳入一個結構體對象時,我們可以根據.來訪問結構體的對應字段。例如:

    type UserInfo struct {
    Name   string
    Gender string
    Age    int
    }
    
    func sayHello(w http.ResponseWriter, r *http.Request) {
        // 解析指定文件生成模板對象
        tmpl, err := template.ParseFiles("./hello.html")
        if err != nil {
            fmt.Println("create template failed, err:", err)
            return
        }
        user := UserInfo{
            Name:   "枯藤",
            Gender: "男",
            Age:    18,
        }
        // 利用給定數據渲染模板,并將結果寫入w
        tmpl.Execute(w, user)
    }
    

    .表示當前對象/結構體user(w只是服務端的一個變量,也保存了user這個結構體而已)

    <body>
    <p>Hello {{.Name}}</p>
    <p>性別:{{.Gender}}</p>
    <p>年齡:{{.Name}}</p>
    </body>
    
  • 模板注釋

    {{/* a comment */}}
    注釋,執行時會忽略。可以多行。注釋不能嵌套,并且必須緊貼分界符始止。
    
  • 管道pipeline

    Go的模板語法中支持使用管道符號|鏈接多個命令,用法和unix下的管道類似:|前面的命令會將運算結果(或返回值)傳遞給后一個命令的最后一個位置。

  • Actions

    以下這些動作基本包含golang模板中常用的動作與含義說明

    {{/* a comment */}}
    注釋,執行時會忽略。可以多行。注釋不能嵌套,并且必須緊貼分界符始止,就像這里表示的一樣。
    {{pipeline}}
        pipeline的值的默認文本表示會被拷貝到輸出里。
    {{if pipeline}} T1 {{end}}
        如果pipeline的值為empty,不產生輸出,否則輸出T1執行結果。不改變dot的值。
        Empty值包括false、0、任意nil指針或者nil接口,任意長度為0的數組、切片、字典。
    {{if pipeline}} T1 {{else}} T0 {{end}}
        如果pipeline的值為empty,輸出T0執行結果,否則輸出T1執行結果。不改變dot的值。
    {{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
        用于簡化if-else鏈條,else action可以直接包含另一個if;等價于:
            {{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}}
    {{range pipeline}} T1 {{end}}
        pipeline的值必須是數組、切片、字典或者通道。
        如果pipeline的值其長度為0,不會有任何輸出;
        否則dot依次設為數組、切片、字典或者通道的每一個成員元素并執行T1;
        如果pipeline的值為字典,且鍵可排序的基本類型,元素也會按鍵的順序排序。
    {{range pipeline}} T1 {{else}} T0 {{end}}
        pipeline的值必須是數組、切片、字典或者通道。
        如果pipeline的值其長度為0,不改變dot的值并執行T0;否則會修改dot并執行T1。
    {{template "name"}}
        執行名為name的模板,提供給模板的參數為nil,如模板不存在輸出為""
    {{template "name" pipeline}}
        執行名為name的模板,提供給模板的參數為pipeline的值。
    {{with pipeline}} T1 {{end}}
        如果pipeline為empty不產生輸出,否則將dot設為pipeline的值并執行T1。不修改外面的dot。
    {{with pipeline}} T1 {{else}} T0 {{end}}
        如果pipeline為empty,不改變dot并執行T0,否則dot設為pipeline的值并執行T1。
    
  • 比較

    eq      如果arg1 == arg2則返回真
    ne      如果arg1 != arg2則返回真
    lt      如果arg1 < arg2則返回真
    le      如果arg1 <= arg2則返回真
    gt      如果arg1 > arg2則返回真
    ge      如果arg1 >= arg2則返回真
    
     {{eq arg1 arg2 arg3}}
    
  • 嵌套模板

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>tmpl test</title>
    </head>
    <body>
    
        <h1>測試嵌套template語法</h1>
        <hr>
        {{template "ul.html"}}
        <hr>
        {{template "ol.html"}}
    </body>
    </html>
    
    {{ define "ol.html"}}
    <h1>這是ol.html</h1>
    <ol>
        <li>AA</li>
        <li>BB</li>
        <li>CC</li>
    </ol>
    {{end}}
    

    ul.html模板 不在當前html文檔內,需要通過服務端template.ParseFiles指定加載的模板頁,才能使用(有點耦合,要是都由前端模板文件去include包含模板可能會更自然些)

    func tmplDemo(w http.ResponseWriter, r *http.Request) {
    tmpl, err := template.ParseFiles("./t.html", "./ul.html")
    if err != nil {
        fmt.Println("create template failed, err:", err)
        return
    }
    user := UserInfo{
        Name:   "枯藤",
        Gender: "男",
        Age:    18,
    }
    tmpl.Execute(w, user)
    

}
```

http包

Go語言內置的net/http包十分的優秀,提供了HTTP客戶端和服務端的實現

  • 客戶端

    resp, err := http.Get("http://www.baidu.com/")
    
    resp, err := http.Post("http://www.9ong.com/post", "image/jpeg", &buf)
    
    resp, err := http.PostForm("http://www.9ong.com/form",
        url.Values{"key": {"Value"}, "id": {"123"}})
    
    if err != nil {
        // handle error
    }
    //使用完response后必須關閉回復的主體
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    

    使用完response后必須關閉回復的主體,總是會有不完美的地方存在哈,還需要自己關閉Body,從編碼的角度看。

  • 帶參數的請求

    帶參數get請求

    apiUrl := "http://127.0.0.1:9090/get"
    // URL param
    data := url.Values{}
    data.Set("name", "枯藤")
    data.Set("age", "18")
    u, err := url.ParseRequestURI(apiUrl)
    if err != nil {
        fmt.Printf("parse url requestUrl failed,err:%v\n", err)
    }
    u.RawQuery = data.Encode() // URL encode
    fmt.Println(u.String())
    resp, err := http.Get(u.String())
    if err != nil {
        fmt.Println("post failed, err:%v\n", err)
        return
    }
    

    帶參數post請求

    // 表單數據
    //contentType := "application/x-www-form-urlencoded"
    //data := "name=jm&age=20"
    // json
    contentType := "application/json"
    data := `{"name":"jm","age":20}`
    resp, err := http.Post(url, contentType, strings.NewReader(data))
    

    看完以下的編寫方式,我們覺得應該有更舒適第三方http庫,只需要:

    http.Get(url,json對象參數|結構體參數)
    http.Post(url,options,data) //options負責設置http頭等信息,data是參數json對象或結構體
    
  • 服務端

```go
// http server

func sayHello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello world")
}

func main() {
    http.HandleFunc("/", sayHello)
    err := http.ListenAndServe(":9527", nil)
    if err != nil {
        fmt.Printf("http server failed, err:%v\n", err)
        return
    }
}
```

自定義server

```go
s := &http.Server{
    Addr:           ":9527",
    Handler:        myHandler,
    ReadTimeout:    10 * time.Second,
    WriteTimeout:   10 * time.Second,
    MaxHeaderBytes: 1 << 20,
}
log.Fatal(s.ListenAndServe())
```

context

在 Go http包的Server中,每一個請求在都有一個對應的 goroutine 去處理。請求處理函數通常會啟動額外的 goroutine 用來訪問后端服務,比如數據庫和RPC服務。用來處理一個請求的 goroutine 通常需要訪問一些與請求特定的數據,比如終端用戶的身份認證信息、驗證相關的token、請求的截止時間。 當一個請求被取消或超時時,所有用來處理該請求的 goroutine 都應該迅速退出,然后系統才能釋放這些 goroutine 占用的資源。

介紹goroutine時,我們看到范例并沒有在main函數里使用context,goroutine也會自動退出。原因是只有一種情況正在運行的goroutine會因為其他goroutine的結束被終止,就是main函數的退出或程序停止執行.

sync.WaitGroup解決了協程協同同步完成問題,context主要為了解決協程協同取消問題

  • Context接口

    context.Context是一個接口,該接口定義了四個需要實現的方法

    type Context interface {
        Deadline() (deadline time.Time, ok bool) //返回當前Context被取消的時間,也就是完成工作的截止時間
        Done() <-chan struct{} //返回一個Channel,這個Channel會在當前工作完成或者上下文被取消之后關閉,多次調用Done方法會返回同一個Channel
        Err() error //返回當前Context結束的原因
        Value(key interface{}) interface{} //從Context中返回鍵對應的值,對于同一個上下文來說,多次調用Value 并傳入相同的Key會返回相同的結果,該方法僅用于傳遞跨API和進程間跟請求域的數據
    }
    

注意:以下介紹的都是函數,并不是創建后context上下問對像的方法,而是context包的函數

  • context.Background函數

  • context.TODO函數

    Go內置兩個函數:Background()和TODO(),這兩個函數分別返回一個實現了Context接口的background和todo。我們代碼中最開始都是以這兩個內置的上下文對象作為最頂層的partent context,衍生出更多的子上下文對象。

    Background()主要用于main函數、初始化以及測試代碼中,作為Context這個樹結構的最頂層的Context,也就是根Context。

    TODO(),它目前還不知道具體的使用場景,如果我們不知道該使用什么Context的時候,可以使用這個。

    background和todo本質上都是emptyCtx結構體類型,是一個不可取消,沒有設置截止時間,沒有攜帶任何值的Context。

  • context.withCancel函數

    WithCancel返回帶有新Done通道的父節點的副本。當調用返回的cancel函數或當關閉父上下文的Done通道時,將關閉返回上下文的Done通道,無論先發生什么情況。

    func gen(ctx context.Context) <-chan int {
        dst := make(chan int)
        n := 1
        go func() {
            for {
                select {
                case <-ctx.Done():
                    return // return結束該goroutine,防止泄露
                case dst <- n:
                    n++
                }
            }
        }()
        return dst
    }
    func main() {
        ctx, cancel := context.WithCancel(context.Background())
        defer cancel() // 當我們取完需要的整數后調用cancel
    
        for n := range gen(ctx) {
            fmt.Println(n)
            if n == 5 {
                break
            }
        }
    }
    
  • context.withDeadline函數

    返回父上下文的副本,并將deadline調整為不遲于d。如果父上下文的deadline已經早于d,則WithDeadline(parent, d)在語義上等同于父上下文。當截止日過期時,當調用返回的cancel函數時,或者當父上下文的Done通道關閉時,返回上下文的Done通道將被關閉,以最先發生的情況為準。

    func main() {
        d := time.Now().Add(50 * time.Millisecond)
        ctx, cancel := context.WithDeadline(context.Background(), d)
    
        // 盡管ctx會過期,但在任何情況下調用它的cancel函數都是很好的實踐。
        // 如果不這樣做,可能會使上下文及其父類存活的時間超過必要的時間。
        defer cancel()
    
        select {
        case <-time.After(1 * time.Second):
            fmt.Println("overslept")
        case <-ctx.Done():
            fmt.Println(ctx.Err())
        }
    }
    
  • context.WithTimeout函數

    func main() {
        // 設置一個50毫秒的超時
        ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
        wg.Add(1)
        go worker(ctx)
        time.Sleep(time.Second * 5)
        cancel() // 通知子goroutine結束
        wg.Wait()
        fmt.Println("over")
    }
    
  • context.WithValue函數

    WithValue返回父節點的副本,其中與key關聯的值為val。

    僅對API和進程間傳遞請求域的數據使用上下文值,而不是使用它來傳遞可選參數給函數。

    type TraceCode string
    
    func worker(){
        ...
        key := TraceCode("TRACE_CODE")
        traceCode, ok := ctx.Value(key).(string) // 在子goroutine中獲取trace code        
        ...
    }
    func main(){
        ...
        // 在系統的入口中設置trace code傳遞給后續啟動的goroutine實現日志數據聚合
        ctx = context.WithValue(ctx, TraceCode("TRACE_CODE"), "2009")
        wg.Add(1)
        go worker(ctx)
        ...
    }
    
  • 關于cancel()函數

    以上范例中的cancel函數,是通過context.With*系列函數返回得到的第二個值,用于通知同一個context下的所有goroutine結束/取消。

golang的context設計,讓我們明白一個道理,能簡單處理好一個問題,就是好的解決方案,沒有高貴之分。

json/xml

  • json

    json可以和map、struct、interface相互轉換

    // 將struct、map轉換成json 字符串
    json.Marshal(struct|map)
    
    //將json字符串轉換成Person結構體
    type Person struct{
        ...
    }
    jsonStr := []byte(`{"age":"18","name":"5lmh.com","marry":false}`)
    var p Person
    json.Unmarshal(jsonStr,&p)
    

    弱類型的js、php可以隨時動態自由的轉換json字符串,這個確實舒服太多,怪不得php開發者總說數組強大。

  • xml

    與json包的方法是一樣,只是數據源不一樣

    xml.Marshal(struct|map)
    xml.Unmarshal(xmlStr,&p)
    
  • msgpack

MSGPack是二進制的json,性能更快,更省空間

需要安裝第三方包:go get -u github.com/vmihailenco/msgpack

```go
msgpack.Marshal(struct|map)
msgpack.Unmarshal(msgpackbinary,&p)
```

reflect反射

反射是指在程序運行期對程序本身進行訪問和修改的能力

reflect包封裝了反射相關的方法:

獲取類型信息:reflect.TypeOf,是靜態的

獲取值信息:reflect.ValueOf,是動態的

反射可以獲取interface類型信息、獲取值信息、修改值信息

反射可以查看結構體字段、類型、方法,修改結構體的值,調用方法

  • 空接口結合反射

    可以通過 空接口 可以表示任何參數,利用反射判斷參數類型

官方標準庫

官方標準庫


轉載請標注來源:golang常用標準庫.html - 9ong.com

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。