strings —字符串函数:
- 包含:
fmt.Println(strings.Contains("abc","a")) // 输出 true
- 分割:
fmt.Println(strings.Split("a,b,c",",")) // 输出 [a b c]
- 拼接:
fmt.Println(strings.Join([]string{"a","b","c"},",")) // 输出 a,b,c
- 去除首尾指定字符:
fmt.Println(strings.Trim("-!abc#","-#!")) // 输出 abc
- 替换:
fmt.Println(strings.Replace("abc","b","-",1)) // 输出 a-c
- 重复字符串:
fmt.Println(strings.Repeat("a",3)) // 输出 aaa
- 检索位置:
fmt.Println(strings.Index("abc","b")) // 输出 1
- 去除空格:
fmt.Println(strings.Fields(" a b c ")) // 输出 [a b c] fmt.Println(strings.TrimSpace(" a b c ")) // 输出 a b c(前后无空格)
- 截取:
fmt.Println(string([]rune("abc你好吗")[1:5])) // 输出 bc你好
- 将字符串转换为 io.reader(goquery 会用到):
fmt.Println(strings.NewReader("abc")) // 输出 &{abc 0 -1}
- 包含:
strconv —字符串转换:
- Append —将其它类型添加到 byte 切片中:
- 整型:
fmt.Println(string(strconv.AppendInt([]byte("abc"),1000,10))) // 输出 abc1000
- 布尔:
fmt.Println(string(strconv.AppendBool([]byte("abc"),false))) // 输出 abcfalse
- 字符串:
fmt.Println(string(strconv.AppendQuote([]byte("abc"),"你好吗"))) // 输出 abc"你好吗"
- 整型:
- Format —其它类型转字符串:
- 整型:
fmt.Println(strconv.Itoa(1000)) // 输出 1000
- 浮点型:
fmt.Println(strconv.FormatFloat(3.1415926, 'g', 3, 64)) // 输出 3.14
- 布尔:
fmt.Println(strconv.FormatBool(false)) // 输出 false
- 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 }
- 整型:
- Parse —字符串转为其它类型:
- 整型:
fmt.Println(strconv.Atoi("1000")) // 输出 1000 <nil>
- 浮点型:
fmt.Println(strconv.ParseFloat("3.1415926",64)) // 输出 3.1415926 <nil>
- 布尔:
fmt.Println(strconv.ParseBool("false")) // 输出 false <nil>
- 整型:
- Quote —特殊字符转义:
fmt.Println(strconv.Quote("abc\r\s\t")) // 输出 "abc\\r\\s\\t"
- 其它:
- string 转 []byte:
str := "abc" fmt.Println([]byte(str))
- []byte 转 string:
bt := []byte{97,98,99} fmt.Println(string(bt))
- string 转 []byte:
- Append —将其它类型添加到 byte 切片中:
encoding —编解码
- encoding/json —生成/解析 json:
- 生成:
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"}]}
- 解析:
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}]}
- 生成:
- encoding/xml —生成/解析 xml:
- 生成:
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>
- 解析:
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}]}
- 生成:
- 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 }
- 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 }
- encoding/json —生成/解析 json:
regexp —正则处理:
- 验证:
fmt.Println(regexp.MatchString("[a-z]*","abc")) // 输出 true <nil>
- 获取:
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]
- 替换:
r, _ := regexp.Compile("[0-9]") str := "a1b2c3" ret := r.ReplaceAllString(str,"") fmt.Println(ret) // 输出 abc
- 分割:
str := "a,b$c" r, _ := regexp.Compile(",|\\$") ret := r.Split(str,-1) fmt.Println(ret) // 输出 [a b c]
- 验证:
crypto —加密/解密:
- 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 }
- 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 }
- 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 }
- crypto/md5 —MD5加密:
time —时间处理:
获取时间缀:
fmt.Println(time.Now().Unix()) // 输出 1589153929
解析/格式化:
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 }
时区转换(伦敦时区转上海时区-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")) }
判断时间是否是零值:
package main import ( "fmt" "time" ) func main() { t1 := time.Now() t2 := time.Time{} fmt.Println("t1: ", t1.IsZero()) fmt.Println("t2: ", t2.IsZero()) }
生成:
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 }
获取整点时间:
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 }
时间加减:
相加:
package main import ( "fmt" "time" ) func main() { now := time.Now() fmt.Println(now.AddDate(1, 2, 3).Format("2006-01-02 15:04:05")) // 获取 1年 2月 3日 之后的时间 fmt.Println(now.Add(time.Hour + 2*time.Minute + 3*time.Second).Format("2006-01-02 15:04:05")) // 获取 1小时 2分钟 3秒 之后的时间 }
相减:
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 }
时间比较:
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 }
计时器:
一次性(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 }
周期性(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
延时调用函数:
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.") }
计时器:
package main import ( "fmt" "time" ) func main() { for { select { case <-time.After(time.Second): fmt.Println("每秒种调用一次!") } } }
net —WEB处理:
net/url —URL处理:
- 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 }
- 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 }
- 表单操作:
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 }
- URL 编/解码:
net/http —网络请求:
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) } }
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) } }
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) } }
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) }
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) } }
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) } }
静态文件处理:
package main import "net/http" func main() { http.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir("./statics")))) http.ListenAndServe(":8080", nil) }
搭建 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) }
检测端口是否开启:
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) }
net/http/pprof —性能监控:
引入
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 { } }
web访问地址:
http://localhost:6060/debug/pprof/
常用分析命令:
# 查看堆栈调用信息 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
查看数据:
top
math —数学相关:
- 生成随机数:
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) }
- 四舍五入:
package main import ( "fmt" "math" ) func main() { fmt.Println(math.Round(3.1415)) } // 输出 3
- 生成随机数:
os —目录/文件操作:
- 目录操作:
package main import "os" func main() { os.Mkdir("tmp", 0755) // 创建目录 os.MkdirAll("tmp/dir1/dir2", 0755) // 递归创建 os.Remove("tmp") // 删除目录 os.RemoveAll("tmp") // 递归删除 }
- 文件操作:
- 创建文件:
package main import "os" func main() { os.Create("test.txt") }
- 打开文件:
package main import ( "fmt" "os" ) func main() { fp,_ := os.OpenFile("test.txt",1,0644) fmt.Println(fp) // 输出 &{0xc00001e1e0} }
- 写文件:
package main import "os" func main() { fp,_ := os.OpenFile("test.txt",2,0644) defer fp.Close() fp.WriteString("Just a test!\r\n") }
- 读文件:
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!
- 删除文件:
package main import "os" func main() { os.Remove("test.txt") }
- 获取 pid(进程ID):
os.Getpid()
- 创建文件:
- 获取命令行参数:
-- 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
- 目录操作:
sort —切片排序:
- 正向排序:
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 }
- 反向排序:
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] }
- 自定义排序:
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]] }
- 判断值是否在切片中:
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) }
- 正向排序:
接口 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) } }
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) }
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() }
切片去重:
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]
判断字典中的 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
删除字典中的 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]
删除切片中指定的元素:
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]
合并切片:
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]
反转切片:
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) }
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
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) }
label 用法:
- 配合 goto:
package main import ( "fmt" "time" ) func main() { label: fmt.Println(1) time.Sleep(time.Second) goto label }
- 跳出外层循环:
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) } } }
- 配合 goto:
结构体 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]
模拟枚举:
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)) }
按照指定顺序遍历 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]) } }
编译/运行命令:
- 编译:
go build *.go 或 go build . 或 go build -v .(编译时显示包名) 或 go build -o ./myPkg .(指定编译后的可执行文件名) 或 go build -ldflags "-w" main.go(去除调试信息,减小可执行文件的大小) 或 go build -gcflags=-m .(对内存进行逃逸分析)
- 运行:
go run *.go 或 go run .
- 手动安装包:
go get .
- 交叉编译:
- 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
- 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
- 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
- linux 系统:
- 编译参数:
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) }
- 执行编译:
go build -ldflags "-X main.Version=1.0.0 -X main.Path=`pwd` -X 'main.Time=`date "+%F %T"`'" -o run test.go
- 运行:
./run
- 输出:
version: 1.0.0 path: /Users/liji/project/goland/test time: 2022-05-31 17:09:30
- 命令解释:
# -ldflags "-X main.Version=1.0.0 ...'": 编译时传入参数 # -o run: 指定输出文件
- 编译:
进度条实现:
package main import ( "fmt" "time" ) // 关键点:\r func main() { for i := 0; i < 10; i++ { fmt.Printf("\r%d", i) time.Sleep(time.Second) } }
反向代理:
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 } }
sync —GO 协程同步:
sync.WaitGroup —计数器(结束单个协程):
一般用法:
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() }
将大数组拆分成小数组进行协程处理:
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) }) }
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) }
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) }
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秒,等待所有协程执行完毕 }
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) }
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() }
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)) }
go routine —协程:
基本用法(在平级的 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 后的业务逻辑耗时 }
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 后的业务逻辑耗时 }
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 后的业务逻辑耗时 }
context 用法:
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 后的业务逻辑耗时 }
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 后的业务逻辑耗时 }
WithTimeout(控制嵌套的 goroutine 在何时结束)
// ... ctx, cancel := context.WithTimeout(context.Background(), time.Second) // ...
WithDeadline(控制嵌套的 goroutine 在何时结束)
// ... ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second)) // ...
- macos
- windows
- linux
- ssh 免密码登录
- 常见服务及分类
- centos7 基本配置
- centos7 安装 harbor2.7.2
- yum 安装 docker20.10.17
- yum 安装 docker-compose1.29.2
- 使用 kuboard-spray 搭建 k8s 集群
- kubebuilder3.2 环境搭建(macOS)
- docker 用法
- k8s1.25 用法
- yum 安装新版 git
- git 常用命令
- openssl 用法
- curl 常见用法
- vim 基本配置
- yum 安装 nginx
- nginx 常见配置
- yum 安装 mysql5.7
- centos7 安装 mysql集群7.5.25
- centos7 安装 mongodb集群4.2.16
- mysql 常见配置
- mongodb 常见用法
- docker 安装 EFK(服务器日志查看)6.4.3
- yum 安装 php7
- php 常见配置
- yum 安装 redis
- centos7 安装 redis集群6.2.3
- redis 常见配置
- centos7 安装 etcd 集群3.3.18
- etcdctl 常用命令
- 源码安装 jdk8
- 源码安装 zookeeper集群3.4.11
- 源码安装 kafka集群2.2.0
- centos7 安装 clickhouse集群19.17
- centos7 安装 elasticsearch6.4.3
- elasticsearch6.4.3 常用API
- centos7 安装 rabbitmq集群3.8.21
- centos7 安装 geth集群1.9.25
- 区块链浏览器 -- explorer
- centos7 安装 fabric2.2.0
- centos7 安装 ipfs集群0.12.2
- yum 安装 sqlite3
- 源码安装 golang
- 服务、进程监控 -- supervisor
- supervisor 集群 -- supervisord-monitor
- 秒级计划任务 -- gocron
- 文档管理 -- mindoc
- 任务管理 -- opms
- 版本控制 -- gitlab16.0.0
- 持续集成 -- jenkins2.385
- 持续集成 -- gitlab-runner
- 服务器监控告警 -- prometheus2.37.9
- CI/CD(基于服务器)
- CI/CD(基于 k8s)
- 聊天服务器 -- rocket.chat
- scp 传输文件
- lrzsz 传输文件
- keepalived-1.3.5 维护服务高可用
- inotify + rsync 文件同步
- nfs 文件服务器
- ngrok 内网穿透
- openvpn 私密隧道
- shadowsocks 翻墙软件
- dhcp 动态 ip 分配服务
- dns 域名解析
- postfix 邮件服务器
- iptables 防火墙
- 暴力破解 hydra
- php
- 包管理 -- composer
- 验证器 -- google
- 数据库 -- illuminate
- 操作mongodb -- mongodb扩展
- 消息队列 -- rabbitmq
- 中文分词 -- jieba
- 文件上传 -- uploader
- 图像处理 -- image
- 发送邮件 -- swiftmailer
- 日志查看 -- viewer
- excel 表格 -- phpspreadsheet
- word 文档 -- phpword
- http 请求 -- guzzle
- redis 缓存 -- predis
- 二维码 -- qr-code
- token 管理 -- php-jwt
- 加密解密 -- encryption
- 多线程/长链接 -- swoole
- 文档生成 -- phpdocumentor
- 打包项目 -- phar
- 安装扩展
- javascript
- golang
- goland 基本配置
- 内置包
- 自定义命令 -- makefile
- 读取配置文件 -- viper
- 获取命令行参数 -- urfave
- web 框架 -- gin
- 接口文档 -- swagger
- 验证器 -- google
- 微服务框架 -- go-zero
- 单元测试 -- go test
- 单元测试打桩工具 -- monkey
- 分布式事务 -- dtm
- 限流器 -- rate
- 降级&熔断 -- hystrix
- mysql 驱动 -- mysql
- ORM -- gorm
- 操作mongodb -- mongo
- 列数据库 -- clickhouse(连接集群)
- 缓存 -- redis
- etcd驱动 -- etcd-client
- 全文搜索 -- elasticsearch
- 消息队列 -- rabbitmq
- 发布订阅 -- mqtt
- k8s客户端 -- client-go
- RBAC -- casbin
- 分布式文件存储 -- ipfs
- im 框架 -- go-socket.io
- im 框架 -- gorilla
- 原生tcp -- net
- tcp框架 -- zinx
- 直播服务器 -- livego
- 多人音视频 -- webrtc
- rpc 框架 -- grpc
- 链路追踪(bug定位) -- opentracing + zipkin
- 游戏服务器框架 -- leaf
- 记录日志 -- logrus
- 字符串编码集转换 -- text
- json 生成/解析
- xml 生成/解析
- html 选择器 -- goquery
- 爬虫框架 -- colly
- 协程池框架 -- ants
- 计划任务框架 -- cron
- 文件监控 -- fsnotify
- 二维码 -- barcode/qrcode
- token 管理 -- golang-jwt
- 以太坊客户端 -- go-ethereum
- 精度值计算 -- decimal
- 依赖注入&控制反转 -- inject
- 启动多个服务 -- errgroup
- 控制并发量 -- semaphore
- 防止缓存击穿 -- singleflight
- 静态文件嵌入 -- embed
- 调用浏览器 -- selenium
- api查询语言 -- graphql
- 热重启 -- fresh
- 数据结构
- 计算机网络
- 计算机操作系统
- 计算机组成原理
- 面试题整理
- 其它
暂无相关搜索结果!
本文档使用 MinDoc 发布
内置包
文档更新时间: 2024-03-24 15:25 作者:lee