1. strings —字符串函数:

    1. 包含:
      fmt.Println(strings.Contains("abc","a")) // 输出 true
    2. 分割:
      fmt.Println(strings.Split("a,b,c",",")) // 输出 [a b c]
    3. 拼接:
      fmt.Println(strings.Join([]string{"a","b","c"},",")) // 输出 a,b,c
    4. 去除首尾指定字符:
      fmt.Println(strings.Trim("-!abc#","-#!")) // 输出 abc
    5. 替换:
      fmt.Println(strings.Replace("abc","b","-",1)) // 输出 a-c
    6. 重复字符串:
      fmt.Println(strings.Repeat("a",3)) // 输出 aaa
    7. 检索位置:
      fmt.Println(strings.Index("abc","b")) // 输出 1
    8. 去除空格:
      fmt.Println(strings.Fields(" a b c "))  // 输出 [a b c]
      fmt.Println(strings.TrimSpace(" a b c "))  // 输出 a b c(前后无空格)
    9. 截取:
      fmt.Println(string([]rune("abc你好吗")[1:5])) // 输出 bc你好
    10. 将字符串转换为 io.reader(goquery 会用到):
      fmt.Println(strings.NewReader("abc")) // 输出 &{abc 0 -1}
  2. strconv —字符串转换:

    1. Append —将其它类型添加到 byte 切片中:
      1. 整型:
        fmt.Println(string(strconv.AppendInt([]byte("abc"),1000,10))) // 输出 abc1000
      2. 布尔:
        fmt.Println(string(strconv.AppendBool([]byte("abc"),false))) // 输出 abcfalse
      3. 字符串:
        fmt.Println(string(strconv.AppendQuote([]byte("abc"),"你好吗"))) // 输出 abc"你好吗"
    2. Format —其它类型转字符串:
      1. 整型:
        fmt.Println(strconv.Itoa(1000)) // 输出 1000
      2. 浮点型:
        fmt.Println(strconv.FormatFloat(3.1415926, 'g', 3, 64)) // 输出 3.14
      3. 布尔:
        fmt.Println(strconv.FormatBool(false)) // 输出 false
      4. interface{}:
         func Strval(value interface{}) (string, error) {
             var key string
             if value == nil {
                 return key, errors.New("value can not be nil")
             }
             switch value.(type) {
             case float64:
                 ft := value.(float64)
                 key = strconv.FormatFloat(ft, 'f', -1, 64)
             case float32:
                 ft := value.(float32)
                 key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
             case int:
                 it := value.(int)
                 key = strconv.Itoa(it)
             case uint:
                 it := value.(uint)
                 key = strconv.Itoa(int(it))
             case int8:
                 it := value.(int8)
                 key = strconv.Itoa(int(it))
             case uint8:
                 it := value.(uint8)
                 key = strconv.Itoa(int(it))
             case int16:
                 it := value.(int16)
                 key = strconv.Itoa(int(it))
             case uint16:
                 it := value.(uint16)
                 key = strconv.Itoa(int(it))
             case int32:
                 it := value.(int32)
                 key = strconv.Itoa(int(it))
             case uint32:
                 it := value.(uint32)
                 key = strconv.Itoa(int(it))
             case int64:
                 it := value.(int64)
                 key = strconv.FormatInt(it, 10)
             case uint64:
                 it := value.(uint64)
                 key = strconv.FormatUint(it, 10)
             case string:
                 key = value.(string)
             case []byte:
                 key = string(value.([]byte))
             default:
                 newValue, err := json.Marshal(value)
                 if err != nil {
                     return "", err
                 }
                 key = string(newValue)
             }
             return key, nil
         }
    3. Parse —字符串转为其它类型:
      1. 整型:
        fmt.Println(strconv.Atoi("1000")) // 输出 1000 <nil>
      2. 浮点型:
        fmt.Println(strconv.ParseFloat("3.1415926",64)) // 输出 3.1415926 <nil>
      3. 布尔:
        fmt.Println(strconv.ParseBool("false")) // 输出 false <nil>
    4. Quote —特殊字符转义:
      fmt.Println(strconv.Quote("abc\r\s\t")) // 输出 "abc\\r\\s\\t"
    5. 其它:
      1. string 转 []byte:
        str := "abc"
        fmt.Println([]byte(str))
      2. []byte 转 string:
        bt := []byte{97,98,99}
        fmt.Println(string(bt))
  3. encoding —编解码

    1. encoding/json —生成/解析 json:
      1. 生成:
         package main
         import (
             "encoding/json"
             "fmt"
         )
         type School struct {
             Students []Student `json:"students"`
         }
         type Student struct {
             Name string `json:"name"`
         }
         func main() {
             data := School{
                 []Student{
                     {Name: "xiaoming"},
                     {Name: "xiaomei"},
                 }}
             res, _ := json.Marshal(data)
             fmt.Println(string(res))
         }
         // 输出:
         // {"students":[{"name":"xiaoming"},{"name":"xiaomei"}]}
      2. 解析:
         package main
         import (
             "encoding/json"
             "fmt"
         )
         type School struct {
             Students []Student `json:"students"`
         }
         type Student struct {
             Name string `json:"name"`
         }
         func main() {
             str := `{"students":[{"name":"xiaoming"},{"name":"xiaomei"}]}`
             var res School
             json.Unmarshal([]byte(str), &res)
             fmt.Println(res)
         }
         // 输出:
         // {[{xiaoming} {xiaomei}]}
    2. encoding/xml —生成/解析 xml:
      1. 生成:
         package main
         import (
             "encoding/xml"
             "fmt"
         )
         type School struct {
             XMLName  xml.Name  `xml:"school"`
             Version  string    `xml:"version,attr"`
             Students []Student `xml:"students"`
         }
         type Student struct {
             Name string `xml:"name"`
         }
         func main() {
             v := &School{Version: "1"}
             v.Students = append(v.Students, Student{Name: "xiaoming"})
             v.Students = append(v.Students, Student{Name: "xiaomei"})
             output, _ := xml.Marshal(v)
             fmt.Println(string([]byte(xml.Header)))
             fmt.Println(string(output))
         }
         // 输出:
         // <?xml version="1.0" encoding="UTF-8"?>
         // <school version="1"><students><name>xiaoming</name></students><students><name>xiaomei</name></students></school>
      2. 解析:
         package main
         import (
             "encoding/xml"
             "fmt"
         )
         type School struct {
             XMLName  xml.Name  `xml:"school"`
             Version  string    `xml:"version,attr"`
             Students []Student `xml:"students"`
         }
         type Student struct {
             Name string `xml:"name"`
         }
         func main() {
             data := []byte(`
                 <?xml version="1.0" encoding="utf-8"?>
                 <school version="1">
                     <students>
                         <name>xiaoming</name>
                     </students>
                     <students>
                         <name>xiaomei</name>
                     </students>
                 </school>
                 `)
             v := School{}
             err := xml.Unmarshal(data, &v)
             if err != nil {
                 fmt.Printf("error: %v", err)
                 return
             }
             fmt.Println(v)
         }
         // 输出:
         // {{ school} 1 [{xiaoming} {xiaomei}]}
    3. encoding/hex —十六进制编/解码:
       package main
       import (
           "encoding/hex"
           "fmt"
       )
       func main() {
           str := []byte("hello")
           // 编码
           encode_str := hex.EncodeToString(str)
           fmt.Println(encode_str)  // 输出 68656c6c6f
           // 解码
           decode_byte, _ := hex.DecodeString(encode_str)
           fmt.Println(string(decode_byte))  // 输出 hello
       }
    4. encoding/base64 —BASE64编/解码:
       package main
       import (
           "encoding/base64"
           "fmt"
       )
       func base64Encode(str string) string {
           return base64.StdEncoding.EncodeToString([]byte(str))
       }
       func base64Decode(str string) (string, error){
           d,e := base64.StdEncoding.DecodeString(str)
           return string(d),e
       }
       func main(){
           str := "hello"
           enc_str := base64Encode(str)
           fmt.Println(string(enc_str))  // 输出 aGVsbG8=
           dec_str,_ := base64Decode(enc_str)
           fmt.Println(string(dec_str))  // 输出 hello
       }
  4. regexp —正则处理:

    1. 验证:
      fmt.Println(regexp.MatchString("[a-z]*","abc")) // 输出 true <nil>
    2. 获取:
      r, _ := regexp.Compile("[0-9]")
      str := "a1b2c3"
      // 获取第一个元素
      m1 := r.FindString(str)
      fmt.Println(m1)  // 输出 1
      // 获取所有
      m2 := r.FindAllString(str,-1)
      fmt.Println(m2)  // 输出 [1 2 3]
    3. 替换:
      r, _ := regexp.Compile("[0-9]")
      str := "a1b2c3"
      ret := r.ReplaceAllString(str,"")
      fmt.Println(ret)  // 输出 abc
    4. 分割:
      str := "a,b$c"
      r, _ := regexp.Compile(",|\\$")
      ret := r.Split(str,-1)
      fmt.Println(ret)  // 输出 [a b c]
  5. crypto —加密/解密:

    1. crypto/md5 —MD5加密:
       package main
       import (
           "crypto/md5"
           "encoding/hex"
           "fmt"
           "io"
       )
       func Md5(str string) string {
           h := md5.New()
           io.WriteString(h, str)
           cipherStr := h.Sum(nil)
           return hex.EncodeToString(cipherStr)
       }
       func main() {
           ret := Md5("123456")
           fmt.Println(ret)  // 输出 e10adc3949ba59abbe56e057f20f883e
       }
    2. crypto/sha1 —SHA1加密:
       package main
       import (
           "crypto/sha1"
           "encoding/hex"
           "io"
           "fmt"
       )
       func Sha1(str string) string {
           h := sha1.New()
           io.WriteString(h, str)
           cipherStr := h.Sum(nil)
           return hex.EncodeToString(cipherStr)
       }
       func main(){
           ret := Sha1("123456")
           fmt.Println(ret)  // 输出 7c4a8d09ca3762af61e59520943dc26494f8941b
       }
    3. crypto/sha256 —SHA256加密:
       package main
       import (
           "crypto/sha256"
           "encoding/hex"
           "io"
           "fmt"
       )
       func Sha256(str string) string {
           h := sha256.New()
           io.WriteString(h, str)
           cipherStr := h.Sum(nil)
           return hex.EncodeToString(cipherStr)
       }
       func main(){
           ret := Sha256("123456")
           fmt.Println(ret)  // 输出 8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
       }
  6. time —时间处理:

    1. 获取时间缀:
      fmt.Println(time.Now().Unix()) // 输出 1589153929

    2. 解析/格式化:

       package main
      
       import (
           "fmt"
           "time"
       )
      
       func main() {
           t, _ := time.ParseInLocation("2006/01月02日 15:04:05", "2019/08月11日 11:50:35", time.Local)
           fmt.Println(t.String())                      // 输出 2019-08-11 11:50:35 +0800 PST
           fmt.Println(t.Year())                        // 输出 2019
           fmt.Println(t.Format("2006-01-02 15:04:05")) // 输出 2019-08-11 12:11:12(时间字符串)
           fmt.Println(t.Unix())                        // 输出 1565495435(时间缀)
           timeInt64 := int64(1565495435)
           fmt.Println(time.Unix(timeInt64, 0)) // 输出 2019-08-11 11:50:35 +0800 PST
       }
    3. 时区转换(伦敦时区转上海时区-UTC0转UTC8):

       package main
       import (
           "fmt"
           "time"
       )
       func main() {
           loc1, _ := time.LoadLocation("Europe/London") // 伦敦时区
           loc2, _ := time.LoadLocation("Asia/Shanghai") // 上海时区
           t, _ := time.ParseInLocation("2006-01-02 15:04:05", "2022-01-01 00:00:00", loc1)
           fmt.Println(t.In(loc2).Format("2006-01-02 15:04:05"))
       }
    4. 判断时间是否是零值:

       package main
      
       import (
           "fmt"
           "time"
       )
      
       func main() {
           t1 := time.Now()
           t2 := time.Time{}
           fmt.Println("t1: ", t1.IsZero())
           fmt.Println("t2: ", t2.IsZero())
       }
    5. 生成:

       package main
       import (
           "fmt"
           "time"
       )
       func main() {
           t := time.Date(2019, 8, 11, 12, 11, 12, 0, time.Local)
           fmt.Println(t.String())  // 输出 2019-08-11 12:11:12 +0800 PST
           fmt.Println(t.Format("2006-01-02 15:04:05"))  // 输出 2019-08-11 12:11:12
           fmt.Println(t.Unix())  // 输出 1565496672
       }
    6. 获取整点时间:

       package main
       import (
           "fmt"
           "time"
       )
       func main() {
           t := time.Now()
           fmt.Println(t.String())  // 输出 2020-05-11 07:55:22.083553 +0800 PST m=+0.000083752
           fmt.Println(t.Truncate(time.Hour))  // 输出 2020-05-11 07:00:00 +0800 PST
           fmt.Println(t.Round(time.Hour))  // 输出 2020-05-11 08:00:00 +0800 PST
       }
    7. 时间加减:

      1. 相加:

         package main
        
         import (
             "fmt"
             "time"
         )
        
         func main() {
             now := time.Now()
             fmt.Println(now.AddDate(1, 2, 3).Format("2006-01-02 15:04:05"))                               // 获取 123日 之后的时间
             fmt.Println(now.Add(time.Hour + 2*time.Minute + 3*time.Second).Format("2006-01-02 15:04:05")) // 获取 1小时 2分钟 3秒 之后的时间
         }
      2. 相减:

         package main
        
         import (
             "fmt"
             "time"
         )
        
         func main() {
             t1 := time.Date(2023, 8, 26, 10, 40, 0, 0, time.Local)
             t2 := time.Date(2023, 8, 27, 10, 40, 0, 0, time.Local)
             duration := t1.Sub(t2)
             fmt.Println(duration.Hours())  // 输出 -24
         }
    8. 时间比较:

       package main
      
       import (
           "fmt"
           "time"
       )
      
       func main() {
           t1 := time.Date(2023, 1, 1, 0, 0, 0, 0, time.Local) // 2023-01-01
           t2 := time.Date(2022, 1, 1, 0, 0, 0, 0, time.Local) // 2022-01-01
           fmt.Println(t1.Before(t2))                          // t1 < t2 ? true : false
           fmt.Println(t1.After(t2))                           // t1 > t2 ? true : false
           fmt.Println(t1.Equal(t2))                           // t1 == t2 ? true : false
       }
    9. 计时器:

      1. 一次性(Timer):

         package main
         import (
             "fmt"
             "time"
         )
         func main() {
             fmt.Println(time.Now().Second())  // 输出 6
             timer := time.NewTimer(time.Second * 3)  // 计时 3秒
             <- timer.C
             fmt.Println(time.Now().Second())  // 输出 9
         }
      2. 周期性(Ticker):

         package main
         import (
             "fmt"
             "time"
         )
         func main() {
             ticker := time.NewTicker(time.Second * 1)
             i := 0
             for {
                 <- ticker.C
                 fmt.Println(time.Now().Second())
                 i++
                 if i == 3 {
                     ticker.Stop() // 停止定时器
                     break
                 }
             }
         }
         // 输出
         13
         14
         15
      3. 延时调用函数:

         package main
         import (
             "fmt"
             "time"
         )
         func main() {
             // 类 javascript 中的 setTimeout
             timer := time.AfterFunc(3*time.Second, func() {
                 fmt.Println("我将在3秒后输出...")
             })
             time.Sleep(2 * time.Second)
             timer.Stop() // 关闭定时器
             fmt.Println("done.")
         }
      4. 计时器:

         package main
        
         import (
             "fmt"
             "time"
         )
        
         func main() {
             for {
                 select {
                 case <-time.After(time.Second):
                     fmt.Println("每秒种调用一次!")
                 }
             }
         }
  7. net —WEB处理:

    1. net/url —URL处理:

      1. URL 编/解码:
         package main
         import (
             "fmt"
             "net/url"
         )
         func main()  {
             encoded := url.QueryEscape("http://www.baidu.com")
             fmt.Println(encoded)  // 输出 http%3A%2F%2Fwww.baidu.com
             decoded,_ := url.QueryUnescape(encoded)
             fmt.Println(decoded)  // 输出 http://www.baidu.com
         }
      2. URL 解析:
         package main
         import (
             "fmt"
             "net/url"
         )
         func main()  {
             url := url.URL{}
             r,_ := url.Parse("http://www.baidu.com/a/b?name=xiaoming#title")
             fmt.Println(r.Scheme)  // 输出 http
             fmt.Println(r.Host)  // 输出 www.baidu.com
             fmt.Println(r.Path)  // 输出 /a/b
             fmt.Println(r.RawQuery)  // 输出 name=xiaoming
             fmt.Println(r.Fragment)  // 输出 title
         }
      3. 表单操作:
         package main
         import (
             "fmt"
             "net/url"
         )
         func main()  {
             form := url.Values{}
             // 添加
             form.Add("a","aa")
             form.Add("b","bb")
             form.Add("c","cc")
             // 修改
             form.Set("a","11")
             // 获取
             fmt.Println(form.Get("a"))  // 输出 11
             // 删除
             form.Del("b")
             // 格式化输出
             fmt.Println(form.Encode())  // 输出 a=11&c=cc
         }
    2. net/http —网络请求:

      1. GET 请求:

         package main
        
         import (
             "fmt"
             "io/ioutil"
             "net/http"
         )
        
         func HttpGet(uri string) (string, error) {
             resp, err := http.Get(uri)
             if resp != nil {
                 defer resp.Body.Close()
             }
             if err != nil {
                 return "", err
             } else {
                 if resp.StatusCode == 200 {
                     bodyReader := resp.Body
                     body, err := ioutil.ReadAll(bodyReader)
                     if err != nil {
                         return "", err
                     } else {
                         return string(body), nil
                     }
                 } else {
                     return "", fmt.Errorf("服务器异常")
                 }
             }
         }
        
         func main() {
             uri := "http://httpbin.org/get?page=1&limit=2"
             ret, err := HttpGet(uri)
             if err != nil {
                 fmt.Println("http get error:", err)
             } else {
                 fmt.Println(ret)
             }
         }
      2. GET 请求(可带请求头):

         package main
        
         import (
             "fmt"
             "io/ioutil"
             "net/http"
         )
        
         func HttpGet(uri string, headers map[string]string) (string, error) {
             req, _ := http.NewRequest("GET", uri, nil)
             if headers != nil {
                 for key, val := range headers {
                     req.Header.Set(key, val)
                 }
             }
             resp, err := (&http.Client{}).Do(req)
             if err != nil {
                 return "", err
             }
             defer resp.Body.Close()
             body, err := ioutil.ReadAll(resp.Body)
             if err != nil {
                 return "", err
             }
             return string(body), nil
         }
        
         func main() {
             uri := "http://httpbin.org/get?page=1&limit=2"
             headers := map[string]string{
                 "token": "xxx",
             }
             ret, err := HttpGet(uri, headers)
             if err != nil {
                 fmt.Println("http get error:", err)
             } else {
                 fmt.Println(ret)
             }
         }
      3. POST 请求:

         package main
        
         import (
             "fmt"
             "io"
             "io/ioutil"
             "net/http"
             "net/url"
         )
        
         func HttpPost(uri string, params url.Values) (string, error) {
             resp, err := http.PostForm(uri, params)
             if resp != nil{
                 defer resp.Body.Close()
             }
             if err != nil {
                 return "", err
             } else {
                 if resp.StatusCode == 200 {
                     bodyReader := resp.Body
                     body, err := ioutil.ReadAll(bodyReader)
                     if err != nil {
                         return "", err
                     } else {
                         return string(body), nil
                     }
                 } else {
                     return "", fmt.Errorf("服务器异常")
                 }
             }
         }
        
         func main() {
             uri := "http://httpbin.org/post?page=1"
             params := url.Values{"names[]": []string{"xiaoming", "xiaomei"}}
             params.Set("age", "20")
             ret, err := HttpPost(uri, params)
             if err != nil {
                 fmt.Println("http post error:", err)
             } else {
                 fmt.Println(ret)
             }
         }
      4. POST 请求(可带请求头):

         package main
        
         import (
             "fmt"
             "io/ioutil"
             "net/http"
             "net/url"
             "strings"
         )
        
         func HttpPost(uri string, params url.Values, headers map[string]string) (string, error) {
             client := &http.Client{}
             req, err := http.NewRequest("POST", uri, strings.NewReader(params.Encode()))
             if err != nil {
                 return "", err
             }
             req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
             req.Header.Add("Content-Encoding", "gzip")
             for key, val := range headers {
                 req.Header.Set(key, val)
             }
             resp, err := client.Do(req)
             if err != nil {
                 return "", err
             }
             if resp != nil {
                 defer resp.Body.Close()
             }
             body, err := ioutil.ReadAll(resp.Body)
             if err != nil {
                 return "", err
             }
             return string(body), nil
         }
        
         func main() {
             params := url.Values{"names[]": []string{"xiaoming", "xiaomei"}}
             params.Set("age", "20")
             headers := map[string]string{
                 "token": "xxx",
             }
             ret, err := HttpPost("http://httpbin.org/post?page=1", params, headers)
             fmt.Println(ret, err)
         }
      5. POST 请求(可上传文件):

         package main
        
         import (
             "bytes"
             "fmt"
             "io"
             "io/ioutil"
             "mime/multipart"
             "net/http"
             "os"
         )
        
         func HttpPost(uri string, data map[string]string, filekey string, path string) (string, error) {
             bodyBuf := &bytes.Buffer{}
             bodyWriter := multipart.NewWriter(bodyBuf)
             // 拼接请求参数
             for k, v := range data {
                 if err := bodyWriter.WriteField(k, v); err != nil {
                     return "", err
                 }
             }
             if filekey != "" && path != "" {
                 // 设置请求文件
                 if fileWriter, err := bodyWriter.CreateFormFile(filekey, path); err != nil {
                     return "", err
                 } else {
                     if fh, err := os.Open(path); err != nil {
                         return "", err
                     } else {
                         defer fh.Close()
                         if _, err := io.Copy(fileWriter, fh); err != nil {
                             return "", err
                         }
                     }
                 }
             }
             contentType := bodyWriter.FormDataContentType()
             if err := bodyWriter.Close(); err != nil {
                 return "", err
             }
             resp, err := http.Post(uri, contentType, bodyBuf)
             if err != nil {
                 return "", err
             }
             if resp != nil{
                 defer resp.Body.Close()
             }
             resp_body, err := ioutil.ReadAll(resp.Body)
             if err != nil {
                 return "", err
             }
             return string(resp_body), nil
         }
        
         func main() {
             ret, err := HttpPost("http://httpbin.org/post?page=1", map[string]string{"name": "xiaoming", "age": "20"}, "file", "./test.js")
             if err != nil {
                 fmt.Println("http post error:", err)
             } else {
                 fmt.Println(ret)
             }
         }
      6. JSON 请求:

         package main
        
         import (
             "fmt"
             "io/ioutil"
             "net/http"
             "strings"
         )
        
         func HttpJson(uri string, str string) (string, error) {
             // 创建客户端实例
             client := &http.Client{}
             // 创建请求实例
             req, err := http.NewRequest("POST", uri, strings.NewReader(str))
             if err != nil {
                 return "", err
             }
             // 增加Header
             req.Header.Add("Content-Type", "application/json")
             req.Header.Add("Content-Encoding", "gzip")
             // 发起请求
             resp, err := client.Do(req)
             if err != nil {
                 return "", err
             }
             if resp != nil {
                 defer resp.Body.Close()
             }
             body, err := ioutil.ReadAll(resp.Body)
             if err != nil {
                 return "", err
             }
             return string(body), nil
         }
        
         func main() {
             uri := "http://httpbin.org/post?page=1"
             str := `
             {
                 "name": "lee",
                 "gender": "male"
             }
         `
             ret, err := HttpJson(uri, str)
             if err != nil {
                 fmt.Println("http json error:", err)
             } else {
                 fmt.Println(ret)
             }
         }
      7. 静态文件处理:

         package main
        
         import "net/http"
        
         func main() {
             http.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir("./statics"))))
             http.ListenAndServe(":8080", nil)
         }
      8. 搭建 web服务器:

         package main
        
         import (
             "context"
             "fmt"
             "html/template"
             "net/http"
             "os"
             "os/signal"
             "strings"
             "syscall"
             "time"
         )
        
         func myHandler(w http.ResponseWriter, r *http.Request) {
             r.ParseForm()       // 解析参数,默认是不会解析的
             fmt.Println(r.Form) // 这些信息是输出到服务器端的打印信息
             fmt.Println("path", r.URL.Path)
             fmt.Println("scheme", r.URL.Scheme)
             fmt.Println(r.Form["url_long"])
             for k, v := range r.Form {
                 fmt.Println("key:", k)
                 fmt.Println("val:", strings.Join(v, ""))
             }
             // 模板解析
             tpl := template.New("")
             tpl, _ = tpl.Parse("Hello {{.}}!!")
             _ = tpl.Execute(os.Stdout, "lee")
             // 输出到客户端
             fmt.Fprintln(w, "Hello world!")
         }
        
         func main() {
             addr := ":8080"
             quit := make(chan os.Signal, 1) // 退出信号
             signal.Notify(quit, syscall.SIGKILL, syscall.SIGQUIT, syscall.SIGINT, syscall.SIGTERM)
             http.HandleFunc("/", myHandler) // 设置访问的路由
             svc := http.Server{
                 Addr:    addr,
                 Handler: http.DefaultServeMux,
             }
        
             // 优雅的停止服务
             go shutdown(quit, &svc)
        
             // 启动服务
             fmt.Printf("server running at:%s \n", addr)
             if err := svc.ListenAndServe(); err != nil {
                 panic("启动服务失败:" + err.Error())
             }
         }
        
         func shutdown(quit chan os.Signal, svc *http.Server) {
             <-quit
             ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
             defer cancel()
             fmt.Println("server shutdown...")
             if err := svc.Shutdown(ctx); err != nil {
                 panic("shutdown error:" + err.Error())
             }
             os.Exit(0)
         }
    3. 检测端口是否开启:

       package main
      
       import (
           "fmt"
           "net"
           "time"
       )
      
       func main() {
           host := "localhost"
           port := 8081
           timeout := time.Second
           network := "tcp"
           address := fmt.Sprintf("%s:%d", host, port)
           conn, err := net.DialTimeout(network, address, timeout)
           if err != nil {
               panic(err)
           }
           _ = conn.Close()
           fmt.Println("address-port exists:", address)
       }
    4. net/http/pprof —性能监控:

      1. 引入pprof

         package main
        
         import (
             "fmt"
             "log"
             "net/http"
             _ "net/http/pprof"
             "runtime"
         )
        
         func Add(a, b int) {
             fmt.Println(a + b)
         }
        
         func main() {
             runtime.SetBlockProfileRate(1)     // 开启对阻塞操作的跟踪,block
             runtime.SetMutexProfileFraction(1) // 开启对锁调用的跟踪,mutex
             Add(1, 2)
             go func() {
                 log.Println(http.ListenAndServe(":6060", nil))
             }()
             for {
             }
         }
      2. web访问地址:
        http://localhost:6060/debug/pprof/

      3. 常用分析命令:

         # 查看堆栈调用信息
         go tool pprof http://localhost:6060/debug/pprof/heap
        
         # 查看 3 秒内的 CPU 信息
         go tool pprof http://localhost:6060/debug/pprof/profile?seconds=3
        
         # 查看 goroutine 阻塞
         go tool pprof http://localhost:6060/debug/pprof/block
        
         # 收集 3 秒内的执行路径
         go tool pprof http://localhost:6060/debug/pprof/trace?seconds=3
        
         # 争用互斥持有者的堆栈跟踪
         go tool pprof http://localhost:6060/debug/pprof/mutex
      4. 查看数据:
        top

  8. math —数学相关:

    1. 生成随机数:
       package main
       import (
           "fmt"
           "math/rand"
           "time"
       )
       func randWithRange(min, max int) int {
           rand.Seed(time.Now().Unix()) // 播种
           if min >= max || min == 0 || max == 0 {
               return max
           }
           return rand.Intn(max-min) + min
       }
       func main() {
           num := randWithRange(30,50)
           fmt.Println(num)
       }
    2. 四舍五入:
       package main
       import (
           "fmt"
           "math"
       )
       func main() {
           fmt.Println(math.Round(3.1415))
       }
       // 输出
       3
  9. os —目录/文件操作:

    1. 目录操作:
       package main
       import "os"
       func main()  {
           os.Mkdir("tmp", 0755)  // 创建目录
           os.MkdirAll("tmp/dir1/dir2", 0755)  // 递归创建
           os.Remove("tmp")  // 删除目录
           os.RemoveAll("tmp")  // 递归删除
       }
    2. 文件操作:
      1. 创建文件:
         package main
         import "os"
         func main()  {
             os.Create("test.txt")
         }
      2. 打开文件:
         package main
         import (
             "fmt"
             "os"
         )
         func main()  {
             fp,_ := os.OpenFile("test.txt",1,0644)
             fmt.Println(fp)  // 输出 &{0xc00001e1e0}
         }
      3. 写文件:
         package main
         import "os"
         func main()  {
             fp,_ := os.OpenFile("test.txt",2,0644)
             defer fp.Close()
             fp.WriteString("Just a test!\r\n")
         }
      4. 读文件:
         package main
         import (
             "fmt"
             "os"
         )
         func main() {
             fl, _ := os.Open("test.txt")
             defer fl.Close()
             buf := make([]byte, 1024)
             for {
                 n, _ := fl.Read(buf)
                 if 0 == n {
                     break
                 }
                 fmt.Println(string(buf[:n]))
             }
         }
         // 输出
         Just a test!
      5. 删除文件:
         package main
         import "os"
         func main() {
             os.Remove("test.txt")
         }
      6. 获取 pid(进程ID):
        os.Getpid()
    3. 获取命令行参数:
       -- test.go
       package main
       import (
           "fmt"
           "os"
           "strconv"
       )
       func main() {
           for idx, args := range os.Args {
               fmt.Println("参数"+strconv.Itoa(idx)+":", args)
           }
       }
       // go run test.go 1 2 3
       // 输出:
       // 参数0: /var/folders/y1/7x7x3ccj27v_k24j_fd0x7wm0000gn/T/go-build2571384448/b001/exe/test
       // 参数1: 1
       // 参数2: 2
       // 参数3: 3
  10. sort —切片排序:

    1. 正向排序:
       package main
       import (
           "fmt"
           "sort"
       )
       func main() {
           nums := []int{5,2,1,3,4}
           // sort.Float64s(floats)
           // sort.Strings(strings)
           sort.Ints(nums)
           fmt.Println(nums)  // 输出 [1 2 3 4 5]
           // 是否已排序
           fmt.Println(sort.IntsAreSorted(nums))  // 输出 true
       }
    2. 反向排序:
       package main
       import (
           "fmt"
           "sort"
       )
       func main() {
           nums := []int{5,2,1,3,4}
           reverse_nums := sort.Reverse(sort.IntSlice(nums))
           sort.Sort(reverse_nums)
           fmt.Println(nums)  // 输出 [5 4 3 2 1]
       }
    3. 自定义排序:
       package main
       import (
           "fmt"
           "sort"
       )
       func main() {
           arr := []map[string]string{
               {"name":"a","age":"1"},
               {"name":"b","age":"3"},
               {"name":"c","age":"2"},
           }
           sort.SliceStable(arr, func(i, j int) bool {
               return arr[i]["age"] < arr[j]["age"]
           })
           fmt.Println(arr)  // 输出 [map[age:1 name:a] map[age:2 name:c] map[age:3 name:b]]
       }
    4. 判断值是否在切片中:
       package main
       import (
           "fmt"
           "sort"
       )
       func InArray(s []int, search int) (int, bool) {
           index := sort.SearchInts(s, search)
           exists := ((index != len(s)) && s[index] == search)
           return index, exists
       }
       func main() {
           s := []int{1, 2, 3}
           index, exists := InArray(s, 2)
           fmt.Println(index, exists)
       }
  11. 接口 interface 的正确用法:

    package main
    import (
        "fmt"
    )
    // * 定义接口
    type Animal interface {
        run(speed int)
    }
    // * 定义实现接口的子类
    type Dog struct {
    }
    func (this Dog) run(speed int) {
        fmt.Println("speed is:",speed)
    }
    // * 定义把接口当做参数的函数
    func ToDo(animal Animal,speed int)  {
        animal.run(speed)
    }
    func main() {
        // 1. 定义类的规范
        var dog Animal = Dog{}
        dog.run(100)
        // 2. 使用接口做参数
        ToDo(dog.(Dog),200)
        // 3. 判断接口类型(避免 panic)
        var i interface{}
        i = 500
        if res, ok := i.(int); ok {
            fmt.Println(res)
        }
    }
  12. reflect —反射:

    package main
    import (
        "fmt"
        "reflect"
    )
    type Student struct {
        Id   int    `json:"id"`
        Name string `json:"name"`
    }
    func (s Student) Say(englishName string) {
        fmt.Println("我叫:", s.Name)
        fmt.Println("我的英文名是:", englishName)
    }
    func main() {
        student := Student{
            Id:   1,
            Name: "小李",
        }
        typeOfStudent := reflect.TypeOf(student)
        valueOfStudent := reflect.ValueOf(student)
        // 获取变量类型
        fmt.Println(typeOfStudent.Kind())
        // 获取变量值
        fmt.Println(valueOfStudent)
        // 判断不同类型的变量是否相等
        fmt.Println(reflect.DeepEqual(student, "abc"))
        // 循环获取结构体中的字段名、字段标签
        for i := 0; i < typeOfStudent.NumField(); i++ {
            field := typeOfStudent.Field(i)
            fmt.Println(field.Name)
            fmt.Println(field.Tag)
        }
        // 获取指定字段中的标签值
        if studentType, ok := typeOfStudent.FieldByName("Name"); ok {
            fmt.Println(studentType.Tag.Get("json"))
        }
        // 通过方法名(字符串)调用结构体中的方法
        methodValue := valueOfStudent.MethodByName("Say")
        args := []reflect.Value{reflect.ValueOf("lee")}
        methodValue.Call(args)
    }
  13. panic - recover 机制:

    package main
    
    import "fmt"
    
    func test() {
        defer func() {
            if p := recover(); p != nil {
                fmt.Println("panic recovered, panic:", p)
            }
        }()
        panic("something wrong...")
    }
    
    func main() {
        test()
    }
  14. 切片去重:

    package main
    import "fmt"
    /**
     * 切片去重
     * @param input []interface{}
     * @return result []interface{}
     */
    func ArrayUnique(input []interface{}) []interface{} {
        result := []interface{}{}
        temp := map[interface{}]string{}
        for _, item := range input {
            // 判断 temp[item] 是否已被赋值
            _,exists := temp[item]
            if exists == false{
                temp[item] = ""
                result = append(result,item)
            }
        }
        return result
    }
    func main() {
        arr := []interface{}{1,2,3,5,1,3,6}
        ret := ArrayUnique(arr)
        fmt.Println(ret)
    }
    // 输出
    [1 2 3 5 6]
  15. 判断字典中的 key 是否已设置(类似于 php 的 isset函数):

    package main
    import "fmt"
    func main() {
        m := map[string]int{
            "a": 1,
            "b": 2,
        }
        _, isset1 := m["a"] // arr["a"] 存在,返回 true
        _, isset2 := m["c"] // arr["c"] 不存在,返回 false
        fmt.Println(isset1, isset2)
    }
    // 输出
    true false
  16. 删除字典中的 key:

    package main
    import "fmt"
    func main() {
        m := map[string]string{
            "a": "aa",
            "b": "bb",
        }
        delete(m,"a")  // 删除 key 为 "a" 的元素
        fmt.Println(m)
    }
    // 输出
    map[b:bb]
  17. 删除切片中指定的元素:

    package main
    import "fmt"
    /**
     * 删除切片中指定的元素
     * @param arr 原切片
     * @param val 要删除的值
     * @return arr 删除后的切片
     */
    func SliceDelete(arr []interface{},val interface{}) []interface{} {
        for k,v := range arr{
            if v == val{
                arr = append(arr[:k],arr[k + 1:]...)
            }
        }
        return arr
    }
    func main() {
        arr := []interface{}{1,2,3,4,5}
        arr = SliceDelete(arr,3)
        fmt.Println(arr)
    }
    // 输出
    [1 2 4 5]
  18. 合并切片:

    package main
    import "fmt"
    func main() {
        a1 := []int{1,2,3}
        a2 := []int{4,5,6}
        a := append(a1,a2...)  // 注意:a2 后面的 ...
        fmt.Println(a)
    }
    // 输出
    [1 2 3 4 5 6]
  19. 反转切片:

    package main
    import "fmt"
    func reverseArray(arr []int) []int {
        for i, j := 0, len(arr)-1; i < j; i, j = i+1, j-1 {
            arr[i], arr[j] = arr[j], arr[i]
        }
        return arr
    }
    func main() {
        arr := []int{5, 4, 3, 2, 1}
        arr1 := reverseArray(arr)
        fmt.Println(arr1)
    }
  20. flag —获取命令行参数:

    -- test.go
    package main
    import (
        "flag"
        "fmt"
        "os"
    )
    func main() {
        a := flag.String("a", "", "参数a")
        b := flag.Bool("b", false, "参数b")
        flag.Parse()
        if *a == "" || *b == false {
            // 打印提示信息
            flag.PrintDefaults()
            os.Exit(1)
        }
        fmt.Println(*a)
        fmt.Println(*b)
    }
    // 运行 go run test.go -a xiaoming -b true
    // 输出
    xiaoming
    true
  21. fmt.printf —格式化输出:

    package main
    import (
        "fmt"
    )
    type myStruct struct {
        x, y int
    }
    func main() {
        // 字符串 - %s
        str := "abc"
        fmt.Printf("%s"+"\n", str)
        // 整型 - %d
        i := 100
        fmt.Printf("%d"+"\n", i)
        // 浮点型 - %f
        f := 3.1415
        fmt.Printf("%.2f"+"\n", f)
        // 布尔型 - %t
        b := true
        fmt.Printf("%t"+"\n", b)
        // 切片/字典/结构体 - %v
        s := []int{1, 2, 3}
        fmt.Printf("%v"+"\n", s)
        m := map[string]string{"a": "aa"}
        fmt.Printf("%v"+"\n", m)
        st := myStruct{
            x: 1,
            y: 2,
        }
        fmt.Printf("%v"+"\n", st)
        // 查看变量类型 - %T
        fmt.Printf("%T"+"\n", st)
    }
  22. label 用法:

    1. 配合 goto:
      package main
      import (
       "fmt"
       "time"
      )
      func main() {
       label: fmt.Println(1)
       time.Sleep(time.Second)
       goto label
      }
    2. 跳出外层循环:
      package main
      import "fmt"
      func main() {
      label:
       for i := 0; i < 10; i++ {
           for j := 0; j < 10; j++ {
               if i == 1 {
                   break label
               }
               fmt.Println(i, j)
           }
       }
      }
  23. 结构体 String()接口用法:

    package main
    import "fmt"
    type Test struct {
        Name string
        Age  int
    }
    func (t Test) String() string {
        return fmt.Sprintf("name: %s, age: %d", t.Name, t.Age)
    }
    func main() {
        arrTest := []Test{
            {
                Name: "lee",
                Age:  30,
            },
            {
                Name: "zhangsan",
                Age:  18,
            },
        }
        fmt.Println(arrTest)
    }
    // 输出:
    [name: lee, age: 30 name: zhangsan, age: 18]
  24. 模拟枚举:

    package main
    
    import (
        "fmt"
    )
    
    type status int
    
    const (
        STOP status = iota + 1 // 从 1 开始
        PEND
        START
        RESTART
    )
    
    func InStatus(input int) bool {
        if status(input) >= STOP && status(input) <= RESTART {
            return true
        }
        return false
    }
    
    func main() {
        fmt.Println(InStatus(0))
        fmt.Println(InStatus(1))
        fmt.Println(InStatus(4))
        fmt.Println(InStatus(5))
    }
  25. 按照指定顺序遍历 map:

    package main
    import (
        "fmt"
        "sort"
    )
    func main() {
        m := map[string]int{
            "5": 5,
            "3": 3,
            "2": 2,
            "1": 1,
            "4": 4,
        }
        fmt.Println("排序前:")
        for k, v := range m {
            fmt.Println(k, v)
        }
        var keys = []string{}
        for key := range m {
            keys = append(keys, key)
        }
        sort.Strings(keys)
        fmt.Println("排序后:")
        for _, key := range keys {
            fmt.Println(key, m[key])
        }
    }
  26. 编译/运行命令:

    1. 编译:
      go build *.go
      或
      go build .
      或
      go build -v .(编译时显示包名)
      或
      go build -o ./myPkg .(指定编译后的可执行文件名)
      或
      go build -ldflags "-w" main.go(去除调试信息,减小可执行文件的大小)
      或
      go build -gcflags=-m .(对内存进行逃逸分析)
    2. 运行:
      go run *.go
      或
      go run .
    3. 手动安装包:
      go get .
    4. 交叉编译:
      1. linux 系统:
        # linux -> mac
        CGO_ENABLED=0
        GOOS=darwin
        GOARCH=amd64
        go build main.go
        # linux -> windows
        CGO_ENABLED=0
        GOOS=windows
        GOARCH=amd64
        go build main.go
      2. mac 系统:
        # mac -> linux
        CGO_ENABLED=0
        GOOS=linux
        GOARCH=amd64
        go build main.go
        # mac -> windows
        CGO_ENABLED=0
        GOOS=windows
        GOARCH=amd64
        go build main.go
      3. windows 系统:
        # windows -> mac
        SET CGO_ENABLED=0
        SET GOOS=darwin
        SET GOARCH=amd64
        go build main.go
        # windows -> linux
        SET CGO_ENABLED=0
        SET GOOS=linux
        SET GOARCH=amd64
        go build main.go
    5. 编译参数:
      1. test.go
        package main
        import "fmt"
        var (
         Version string
         Path    string
         Time    string
        )
        func main() {
         fmt.Println("version:", Version)
         fmt.Println("path:", Path)
         fmt.Println("time:", Time)
        }
      2. 执行编译:
        go build -ldflags "-X main.Version=1.0.0 -X main.Path=`pwd` -X 'main.Time=`date "+%F %T"`'" -o run test.go
      3. 运行:
        ./run
      4. 输出:
        version: 1.0.0
        path: /Users/liji/project/goland/test
        time: 2022-05-31 17:09:30
      5. 命令解释:
        # -ldflags "-X main.Version=1.0.0 ...'": 编译时传入参数
        # -o run: 指定输出文件
  27. 进度条实现:

    package main
    import (
        "fmt"
        "time"
    )
    // 关键点:\r
    func main() {
        for i := 0; i < 10; i++ {
            fmt.Printf("\r%d", i)
            time.Sleep(time.Second)
        }
    }
  28. 反向代理:

    package main
    import (
        "fmt"
        "net/http"
        "net/http/httputil"
        "net/url"
    )
    func proxy(w http.ResponseWriter, r *http.Request) {
        u, _ := url.Parse("https://www.google.com/")
        proxy := httputil.NewSingleHostReverseProxy(u)
        proxy.ServeHTTP(w, r)
    }
    func main() {
        http.HandleFunc("/proxy", proxy)
        err := http.ListenAndServe(":8080", nil)
        if err != nil {
            fmt.Println("HTTP server failed,err:", err)
            return
        }
    }
  29. sync —GO 协程同步:

    1. sync.WaitGroup —计数器(结束单个协程):

      1. 一般用法:

         package main
         import (
             "fmt"
             "sync"
         )
         func main() {
             wg := sync.WaitGroup{}
             for i := 0; i < 3; i++ {
                 wg.Add(1)
                 go func(i int, wg *sync.WaitGroup) {
                     fmt.Println(i)
                     wg.Done()
                 }(i, &wg)
             }
             wg.Wait()
         }
      2. 将大数组拆分成小数组进行协程处理:

         package main
        
         import (
             "fmt"
             "sync"
         )
        
         func goSplitArr(arr []interface{}, goroutineNum int, handler func(arr []interface{})) {
             wg := sync.WaitGroup{}
             arrLen := len(arr)
             if goroutineNum > arrLen {
                 goroutineNum = arrLen
             }
             if arrLen < 1 {
                 return
             }
             pieceNum := arrLen / goroutineNum
             for i := 0; i < goroutineNum; i++ {
                 wg.Add(1)
                 var pieceArr []interface{}
                 if i == goroutineNum-1 {
                     pieceArr = arr[i*pieceNum:]
                 } else {
                     pieceArr = arr[i*pieceNum : (i+1)*pieceNum]
                 }
                 go func(arr []interface{}) {
                     handler(arr)
                     wg.Done()
                 }(pieceArr)
             }
             wg.Wait()
         }
        
         func main() {
             arr := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
             goroutineNum := 3
             goSplitArr(arr, goroutineNum, func(arr []interface{}) {
                 fmt.Println(arr)
             })
         }
    2. sync.Mutex —互斥锁:

       package main
       import (
           "fmt"
           "sync"
       )
       func main() {
           arr := make([]int, 0)
           mu := sync.Mutex{}
           wg := sync.WaitGroup{}
           for i := 0; i < 100; i++ {
               wg.Add(1)
               go func(i int, wg *sync.WaitGroup, arr *[]int, mu *sync.Mutex) {
                   mu.Lock()
                   defer mu.Unlock()
                   *arr = append(*arr, i)
                   wg.Done()
               }(i, &wg, &arr, &mu)
           }
           wg.Wait()
           fmt.Println(len(arr), arr)
       }
    3. sync.RWMutex -读写锁:

       package main
       import (
           "fmt"
           "sync"
           "time"
       )
       func read(data map[string]int, key string, rw *sync.RWMutex) {
           rw.RLock() // 读锁
           defer rw.RUnlock()
           fmt.Println(data[key])
       }
       func write(data map[string]int, key string, value int, rw *sync.RWMutex) {
           rw.Lock() // 写锁
           defer rw.Unlock()
           data[key] = value
       }
       func main() {
           data := map[string]int{
               "a": 1,
               "b": 2,
               "c": 3,
           }
           rw := sync.RWMutex{}
           for key, value := range data {
               go write(data, key, value+10, &rw)
               go read(data, key, &rw)
           }
           time.Sleep(time.Second)
           fmt.Println(data)
       }
    4. sync.Cond —带控制条件的锁:

       package main
      
       import (
           "fmt"
           "sync"
           "time"
       )
      
       func main() {
           cond := sync.NewCond(&sync.Mutex{})
           //cond := sync.NewCond(&sync.RWMutex{})
           for i := 0; i < 10; i++ {
               go func(num int) {
                   cond.L.Lock()         // 获取锁
                   defer cond.L.Unlock() // 释放锁
                   cond.Wait()           // 等待通知,阻塞当前goroutine
                   // todo: 执行业务
                   fmt.Println(num)
               }(i)
           }
           time.Sleep(time.Second)
           cond.Signal() // 1秒后下发一个通知(解除单个阻塞的协程)
           time.Sleep(time.Second)
           cond.Signal() // 2秒后下发一个通知(解除单个阻塞的协程)
           time.Sleep(time.Second)
           cond.Broadcast()        // 3秒后给所有协程下发通知(解除所有阻塞的协程)
           time.Sleep(time.Second) // 睡眠1秒,等待所有协程执行完毕
       }
    5. sync.Once -保证 func 只被调用一次:

       package main
       import (
           "fmt"
           "sync"
       )
       var num = 1
       var so sync.Once
       func loadConf() {
           so.Do(func() {
               num++
           })
       }
       func main() {
           loadConf()
           loadConf()
           loadConf()
           fmt.Println(num)
       }
    6. sync.Map -并发安全的 map:

       package main
       import (
           "fmt"
           "sync"
       )
       func main() {
           //m := map[int]int{}
           m := sync.Map{}
           wg := sync.WaitGroup{}
           for i := 0; i < 10; i++ {
               wg.Add(1)
               go func(i int) {
                   //m[i] = i
                   //if value, ok := m[i]; ok {
                   //    fmt.Println(value)  // 报错
                   //}
                   m.Store(i, i)
                   if value, ok := m.Load(i); ok {
                       fmt.Println(value) // 正常输出
                   }
                   wg.Done()
               }(i)
           }
           wg.Wait()
       }
    7. sync/atomic -变量原子操作:

       package main
      
       import (
           "fmt"
           "sync"
           "sync/atomic"
       )
      
       func main() {
           var num int32
           var wg sync.WaitGroup
           wg.Add(4)
           go func() {
               // 将 num 的值设为 50
               atomic.StoreInt32(&num, 50)
               fmt.Printf("store, num = %d \n", atomic.LoadInt32(&num))
               wg.Done()
           }()
           go func() {
               // 将 num 的值加 1
               atomic.AddInt32(&num, 1)
               fmt.Printf("add, num = %d \n", atomic.LoadInt32(&num))
               wg.Done()
           }()
           go func() {
               // 将 num 设为 100,并返回 num 之前的值
               old := atomic.SwapInt32(&num, 100)
               fmt.Printf("swap, num = %d, old = %d \n", atomic.LoadInt32(&num), old)
               wg.Done()
           }()
           go func() {
               // 如果 num 的值为 0,则将 num 设为 200
               ok := atomic.CompareAndSwapInt32(&num, 0, 200)
               fmt.Printf("compareAndSwap, num = %d, ok = %t \n", atomic.LoadInt32(&num), ok)
               wg.Done()
           }()
           wg.Wait()
           fmt.Printf("最终值, num = %d \n", atomic.LoadInt32(&num))
       }
  30. go routine —协程:

    1. 基本用法(在平级的 goroutine 中异步获取执行结果):

       package main
      
       import (
           "fmt"
           "sync"
           "time"
       )
      
       func main() {
           wg := sync.WaitGroup{}
           ch1 := make(chan int)
           ch2 := make(chan int)
           wg.Add(1)
           go func() {
               defer wg.Done()
               time.Sleep(time.Second) // 模拟执行业务逻辑耗时
               ch1 <- 1
           }()
           wg.Add(1)
           go func() {
               defer wg.Done()
               time.Sleep(2 * time.Second) // 模拟执行业务逻辑耗时
               ch2 <- 2
           }()
           go func() {
               wg.Wait()
               close(ch1)
               close(ch2)
           }()
           v1 := <-ch1
           v2 := <-ch2
           fmt.Println("v1:", v1)
           fmt.Println("v2:", v2)
           time.Sleep(time.Second) // 模拟退出 chan 后的业务逻辑耗时
       }
    2. for + range(监听单个 chan,控制 goroutine 在满足条件时结束):

       package main
      
       import (
           "fmt"
           "sync"
           "time"
       )
      
       func main() {
           wg := sync.WaitGroup{}
           arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
           ch := make(chan int)
           for _, item := range arr {
               wg.Add(1)
               go func(value int) {
                   defer wg.Done()
                   time.Sleep(time.Second) // 模拟执行业务逻辑耗时
                   ch <- value
               }(item)
           }
           go func() {
               wg.Wait()
               close(ch)
           }()
           for value := range ch {
               if value == 5 {
                   break
               }
               fmt.Println("value:", value)
           }
           time.Sleep(time.Second) // 模拟退出 chan 后的业务逻辑耗时
       }
    3. for + select(监听多个 chan,控制平级的 goroutine 在满足条件时结束):

       package main
      
       import (
           "fmt"
           "sync"
           "time"
       )
      
       func main() {
           wg := sync.WaitGroup{}
           arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
           ch1 := make(chan int)
           ch2 := make(chan bool)
           for _, item := range arr {
               wg.Add(1)
               go func(value int) {
                   defer wg.Done()
                   time.Sleep(time.Second) // 模拟执行业务逻辑耗时
                   ch1 <- value
                   if value == 8 {
                       ch2 <- true
                   }
               }(item)
           }
           go func() {
               wg.Wait()
               close(ch1)
               close(ch2)
           }()
       label:
           for {
               select {
               case v, ok := <-ch1:
                   if !ok {
                       break label
                   }
                   if v == 5 {
                       fmt.Println("ch1 closed")
                       break label
                   }
                   fmt.Println("value:", v)
               case b, ok := <-ch2:
                   if !ok {
                       break label
                   }
                   if b == true {
                       fmt.Println("ch2 closed")
                       break label
                   }
               }
           }
           time.Sleep(time.Second) // 模拟退出 chan 后的业务逻辑耗时
       }
    4. context 用法:

      1. WithCancel(控制嵌套的 goroutine 在满足条件时结束)

         package main
        
         import (
             "context"
             "fmt"
             "time"
         )
        
         func father(ch chan int, cancel context.CancelFunc) {
             go child(ch, cancel)
             for i := 0; i < 10; i++ {
                 go func(value int) {
                     time.Sleep(time.Second) // 模拟执行业务逻辑耗时
                     ch <- value
                     if value == 5 {
                         cancel()
                     }
                 }(i)
             }
         }
         func child(ch chan int, cancel context.CancelFunc) {
             for i := 11; i < 20; i++ {
                 go func(value int) {
                     time.Sleep(time.Second) // 模拟执行业务逻辑耗时
                     ch <- value
                     if value == 15 {
                         cancel()
                     }
                 }(i)
             }
         }
        
         func main() {
             ch := make(chan int)
             ctx, cancel := context.WithCancel(context.Background())
             go father(ch, cancel)
         label:
             for {
                 select {
                 case v, ok := <-ch:
                     if !ok {
                         break label
                     }
                     if v == 5 {
                         fmt.Println("ch closed!")
                         break label
                     }
                     fmt.Println("value:", v)
                 case <-ctx.Done():
                     fmt.Println("cancel called!")
                     break label
                 }
             }
             time.Sleep(time.Second) // 模拟退出 chan 后的业务逻辑耗时
         }
      2. WithValue(在嵌套的 goroutine 之间传递数据)

         package main
        
         import (
             "context"
             "fmt"
             "time"
         )
        
         func father(ctx context.Context, ch chan int, cancel context.CancelFunc) {
             ctx = context.WithValue(ctx, "father-key", "father-value")
             printCtxValue(ctx)
             go child(ctx, ch, cancel)
             for i := 0; i < 10; i++ {
                 go func(value int) {
                     time.Sleep(time.Second) // 模拟执行业务逻辑耗时
                     ch <- value
                     if value == 5 {
                         cancel()
                     }
                 }(i)
             }
         }
         func child(ctx context.Context, ch chan int, cancel context.CancelFunc) {
             ctx = context.WithValue(ctx, "child-key", "child-value")
             printCtxValue(ctx)
             for i := 11; i < 20; i++ {
                 go func(value int) {
                     time.Sleep(time.Second) // 模拟执行业务逻辑耗时
                     ch <- value
                     if value == 15 {
                         cancel()
                     }
                 }(i)
             }
         }
        
         func printCtxValue(ctx context.Context) {
             fmt.Println("main-key:", ctx.Value("main-key"))
             fmt.Println("father-key:", ctx.Value("father-key"))
             fmt.Println("child-key:", ctx.Value("child-key"))
         }
        
         func main() {
             ch := make(chan int)
             ctx, cancel := context.WithCancel(context.Background())
             ctx = context.WithValue(ctx, "main-key", "main-value")
             printCtxValue(ctx)
             go father(ctx, ch, cancel)
         label:
             for {
                 select {
                 case v, ok := <-ch:
                     if !ok {
                         break label
                     }
                     if v == 5 {
                         fmt.Println("ch closed!")
                         break label
                     }
                     fmt.Println("value:", v)
                 case <-ctx.Done():
                     fmt.Println("cancel called!")
                     break label
                 }
             }
             time.Sleep(time.Second) // 模拟退出 chan 后的业务逻辑耗时
         }
      3. WithTimeout(控制嵌套的 goroutine 在何时结束)

        // ...
        ctx, cancel := context.WithTimeout(context.Background(), time.Second)
        // ...
      4. WithDeadline(控制嵌套的 goroutine 在何时结束)

        // ...
        ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second))
        // ...
文档更新时间: 2024-03-24 15:25   作者:lee