云原生时代崛起的编程语言Go常用标准库实战

科技资讯 投稿 7300 0 评论

云原生时代崛起的编程语言Go常用标准库实战

目录
    基础标准库
    • 简述
    • 字符串-string
      • 底层结构
      • 函数
      • 长度
      • 格式化输出
    • 模版-template
        text/template
    • html/template
  • 正则表达式-regexp
  • 编码-encoding
      Base64
  • JSON
  • XML
  • 时间-time
  • 网络-net
      URL
  • HTTP客户端和服务端
  • 加密
  • IO操作
      读写文件
  • 环境变量
  • 命令行
  • 数据库
  • 排序-sort
  • 测试和基准测试
  • 基础标准库

    简述

    Go语言标准库包名 功 能
    bufio 带缓冲的 I/O 操作
    bytes 实现字节操作
    container 封装堆、列表和环形列表等容器
    crypto 加密算法
    database 数据库驱动和接口
    debug 各种调试文件格式访问及调试功能
    encoding 常见算法如 JSON、XML、Base64 等
    flag 命令行解析
    fmt 格式化操作
    go Go 语言的词法、语法树、类型等。可通过这个包进行代码信息提取和修改
    html HTML 转义及模板系统
    image 常见图形格式的访问及生成
    io 实现 I/O 原始访问接口及访问封装
    log 用于日志记录和控制台输出
    math 数学库
    net 网络库,支持 Socket、HTTP、邮件、RPC、SMTP 等
    os 操作系统平台不依赖平台操作封装
    path 兼容各操作系统的路径操作实用函数
    plugin Go 1.7 加入的插件系统。支持将代码编译为插件,按需加载
    reflect 语言反射支持。可以动态获得代码中的类型信息,获取和修改变量的值
    regexp 正则表达式封装
    runtime 运行时接口
    sort 排序接口
    strings 字符串转换、解析及实用函数
    sync 提供同步原语,如互斥锁和条件变量(上篇文章有专门讲解)
    time 时间接口
    text 文本模板及 Token 词法器

    字符串-string

    底层结构

    标准库的strings包提供了许多有用的与字符串相关的函数。Go字符串底层的数据结构在runtime/strings.go中定义如下:

    函数

    package main
    
    import (
    	"fmt"
    	s "strings"
    	"unsafe"
    
    
    var p = fmt.Println
    
    func main( {
    	p(unsafe.Sizeof("anyStrings"
    	p(unsafe.Sizeof("anyStringsMoreThenLength"
    	p("Contains:  ", s.Contains("test", "es"
    	p("Count:     ", s.Count("test", "t"
    	p("HasPrefix: ", s.HasPrefix("test", "te"
    	p("HasSuffix: ", s.HasSuffix("test", "st"
    	p("Index:     ", s.Index("test", "e"
    	p("Join:      ", s.Join([]string{"a", "b"}, "-"
    	p("Repeat:    ", s.Repeat("a", 5
    	p("Replace:   ", s.Replace("foo", "o", "0", -1
    	p("Replace:   ", s.Replace("foo", "o", "0", 1
    	p("Split:     ", s.Split("a-b-c-d-e", "-"
    	p("ToLower:   ", s.ToLower("TEST"
    	p("ToUpper:   ", s.ToUpper("test"
    }
    

    长度

      Go 语言的内建函数 len(,可以用来获取切片、字符串、通道(channel)等的长度,
    • Go 语言的字符串都以 UTF-8 格式保存,每个中文占用 3 个字节,因此使用 len( 获得两个中文文字对应的 6 个字节;
    • 针对ASCII 字符串长度使用 len( 函数,Unicode 字符串长度使用 utf8.RuneCountInString( 函数。如果没有使用 Unicode,汉字则显示为乱码。
    • ASCII 字符串遍历直接使用下标;Unicode 字符串遍历用 for range
    • bytes.Buffer实现字符串拼接。
    package main
    
    import (
    	"bytes"
    	"fmt"
    	"unicode/utf8"
    
    
    var p = fmt.Println
    
    func main( {
    	str1 := "Hello World!"
    	str2 := "你好"
    	fmt.Println(len(str1                          // 12
    	fmt.Println(len(str2                          // 6
    	fmt.Println(utf8.RuneCountInString(str2       // 2
    	fmt.Println(utf8.RuneCountInString("你好,world" // 8
    
    	// 声明字节缓冲
    	var stringBuilder bytes.Buffer
    	// 把字符串写入缓冲
    	stringBuilder.WriteString(str1
    	stringBuilder.WriteString(str2
    	// 将缓冲以字符串形式输出
    	fmt.Println(stringBuilder.String(
    
    	theme := "狙击 start"
    	for i := 0; i < len(theme; i++ {
    		fmt.Printf("ascii: %c  %d\n", theme[i], theme[i]
    	}
    
    	for _, s := range theme {
    		fmt.Printf("Unicode: %c  %d\n", s, s
    	}
    }
    

    格式化输出

    package main
    
    import (
    	"fmt"
    	"os"
    
    
    type point struct {
    	x, y int
    }
    
    func main( {
    
    	p := point{1, 2}
    	fmt.Printf("struct1: %v\n", p
    
    	fmt.Printf("struct2: %+v\n", p
    
    	fmt.Printf("struct3: %#v\n", p
    
    	fmt.Printf("type: %T\n", p
    
    	fmt.Printf("bool: %t\n", true
    
    	fmt.Printf("int: %d\n", 123
    
    	fmt.Printf("bin: %b\n", 14
    
    	fmt.Printf("char: %c\n", 33
    
    	fmt.Printf("hex: %x\n", 456
    
    	fmt.Printf("float1: %f\n", 78.9
    
    	fmt.Printf("float2: %e\n", 123400000.0
    	fmt.Printf("float3: %E\n", 123400000.0
    
    	fmt.Printf("str1: %s\n", "\"string\""
    
    	fmt.Printf("str2: %q\n", "\"string\""
    
    	fmt.Printf("str3: %x\n", "hex this"
    
    	fmt.Printf("pointer: %p\n", &p
    
    	fmt.Printf("width2: |%6d|%6d|\n", 12, 345
    
    	fmt.Printf("width3: |%6.2f|%6.2f|\n", 1.2, 3.45
    
    	fmt.Printf("width4: |%-6.2f|%-6.2f|\n", 1.2, 3.45
    
    	fmt.Printf("width5: |%6s|%6s|\n", "foo", "b"
    
    	fmt.Printf("width5: |%-6s|%-6s|\n", "foo", "b"
    
    	s := fmt.Sprintf("sprintf: a %s", "string"
    	fmt.Println(s
    
    	fmt.Fprintf(os.Stderr, "io: an %s\n", "error"
    }
    

    模版-template

    text/template

    Go提供了text/template和html/template这两个模板包,这两个包的部分函数看起来非常相似,实际功能也确实如此

    package main
    
    import (
    	"os"
    	"text/template"
    
    
    type Inventory struct {
    	Username string
    	Phone    uint
    	Tag      bool
    	Sex      string
    }
    
    func main( {
    	t1 := template.New("t1"
    	t1, err := t1.Parse("Value is {{.}}\n"
    	if err != nil {
    		panic(err
    	}
    
    	t1 = template.Must(t1.Parse("Value: {{.}}\n"
    
    	t1.Execute(os.Stdout, "some text"
    	t1.Execute(os.Stdout, 5
    	t1.Execute(os.Stdout, []string{
    		"Go",
    		"Rust",
    		"C++",
    		"C#",
    	}
    
    	Create := func(name, t string *template.Template {
    		return template.Must(template.New(name.Parse(t
    	}
    
    	t2 := Create("t2", "Name: {{.Name}}\n"
    
    	t2.Execute(os.Stdout, struct {
    		Name string
    	}{"Jane Doe"}
    
    	t2.Execute(os.Stdout, map[string]string{
    		"Name": "Mickey Mouse",
    	}
    
    	t3 := Create("t3",
    		"{{if . -}} yes {{else -}} no {{end}}\n"
    	t3.Execute(os.Stdout, "not empty"
    	t3.Execute(os.Stdout, ""
    
    	t4 := Create("t4",
    		"Range: {{range .}}{{.}} {{end}}\n"
    	t4.Execute(os.Stdout,
    		[]string{
    			"Go",
    			"Rust",
    			"C++",
    			"C#",
    		}
    
    	sweaters := Inventory{"移动", 10086, false, "难"}
    
    	content := `{{.Phone}} of {{.Username}} {{if .Tag }} tag=true {{else}}   tag=false {{end}}`
    	tmpl, err := template.New("test".Parse(content
    	//{{.Phone}}获取的是struct对象中的Phone字段的值
    	if err != nil {
    		panic(err
    	}
    	err = tmpl.Execute(os.Stdout, sweaters // 10086 of 移动  tag=true
    	if err != nil {
    		panic(err
    	}
    }
    

    html/template

    package main
    
    import (
    	"html/template"
    	"net/http"
    
    
    func tmpl(w http.ResponseWriter, r *http.Request {
    	t1, err := template.ParseFiles("test.html"
    	if err != nil {
    		panic(err
    	}
    	t1.Execute(w, "hello world"
    }
    
    func main( {
    	server := http.Server{
    		Addr: "127.0.0.1:8080",
    	}
    	http.HandleFunc("/tmpl", tmpl
    	server.ListenAndServe(
    }
    

    创建test.html

    <!DOCTYPE html>
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>Go Web</title>
    </head>
    <body>
    {{ . }}
    </body>
    </html>
    

    访问测试地址http://localhost:8080/tmpl

    正则表达式-regexp

      MatchString:regexp.MatchString(用来匹配子字符串。下面这个例子是检查字符串是否以Golang开头。我们使用^来匹配字符串中以文本的开始。我们使用^Golang作为正则表达式进行匹配。
    • Compile:Compile( 或者 MustCompile(创建一个编译好的正则表达式对象。假如正则表达式非法,那么Compile(方法会返回error,而MustCompile(编译非法正则表达式时不会返回error,而是会panic。如果你想要很好的性能,不要在使用的时候才调用Compile(临时进行编译,而是预先调用Compile(编译好正则表达式对象。
    • FindString:FindString(用来返回第一个匹配的结果。如果没有匹配的字符串,那么它会返回一个空的字符串,当然如果你的正则表达式就是要匹配空字符串的话,它也会返回空字符串。使用 FindStringIndex 或者 FindStringSubmatch可以区分这两种情况。
      • FindStringIndex:FindStringIndex(可以得到匹配的字符串在整体字符串中的索引位置。如果没有匹配的字符串,它会返回nil值。
      • FindStringSubmatch:FindStringSubmatch( 除了返回匹配的字符串外,还会返回子表达式的匹配项。如果没有匹配项,则返回nil值。
    • FindAllString:FindString方法的All版本,它返回所有匹配的字符串的slice。如果返回nil值代表没有匹配的字符串。
    • ReplaceAllString :用来替换所有匹配的字符串,返回一个源字符串的拷贝。

    Go中与regexp相关的一些常见示例

    package main
    
    import (
    	"bytes"
    	"fmt"
    	"regexp"
    
    
    func main( {
    
    	match, _ := regexp.MatchString("p([a-z]+ch", "peach"
    	fmt.Println(match
    
    	r, _ := regexp.Compile("p([a-z]+ch"
    
    	fmt.Println(r.MatchString("peach"
    
    	fmt.Println(r.FindString("peach punch"
    
    	fmt.Println("idx:", r.FindStringIndex("peach punch"
    
    	fmt.Println(r.FindStringSubmatch("peach punch"
    
    	fmt.Println(r.FindStringSubmatchIndex("peach punch"
    
    	fmt.Println(r.FindAllString("peach punch pinch", -1
    
    	fmt.Println("all:", r.FindAllStringSubmatchIndex(
    		"peach punch pinch", -1
    
    	fmt.Println(r.FindAllString("peach punch pinch", 2
    
    	fmt.Println(r.Match([]byte("peach"
    
    	r = regexp.MustCompile("p([a-z]+ch"
    	fmt.Println("regexp:", r
    
    	fmt.Println(r.ReplaceAllString("a peach", "<fruit>"
    
    	in := []byte("a peach"
    	out := r.ReplaceAllFunc(in, bytes.ToUpper
    	fmt.Println(string(out
    }
    

    编码-encoding

    encoding 包是 Go 标准库中的一个重要包,主要用于数据编码和解码。encoding 包中包含了许多常用的数据编码和解码算法,如 JSON、XML、CSV、Base64 等,这些算法可以帮助我们将数据从一种格式转换为另一种格式,便于在不同的系统之间传输和处理。

    Base64

    package main
    
    import (
    	b64 "encoding/base64"
    	"fmt"
    
    
    func main( {
    
    	data := "abc123!?$*&('-=@~"
    
    	sEnc := b64.StdEncoding.EncodeToString([]byte(data
    	fmt.Println(sEnc
    
    	sDec, _ := b64.StdEncoding.DecodeString(sEnc
    	fmt.Println(string(sDec
    	fmt.Println(
    
    	uEnc := b64.URLEncoding.EncodeToString([]byte(data
    	fmt.Println(uEnc
    	uDec, _ := b64.URLEncoding.DecodeString(uEnc
    	fmt.Println(string(uDec
    }
    

    JSON

    ~~~go
    package main
    
    import (
    	"encoding/json"
    	"fmt"
    	"os"
    
    
    type response1 struct {
    	Page   int
    	Fruits []string
    }
    
    type response2 struct {
    	Page   int      `json:"page"`
    	Fruits []string `json:"fruits"`
    }
    
    func main( {
    
    	bolB, _ := json.Marshal(true
    	fmt.Println(string(bolB
    
    	intB, _ := json.Marshal(1
    	fmt.Println(string(intB
    
    	fltB, _ := json.Marshal(2.34
    	fmt.Println(string(fltB
    
    	strB, _ := json.Marshal("gopher"
    	fmt.Println(string(strB
    
    	slcD := []string{"apple", "peach", "pear"}
    	slcB, _ := json.Marshal(slcD
    	fmt.Println(string(slcB
    
    	mapD := map[string]int{"apple": 5, "lettuce": 7}
    	mapB, _ := json.Marshal(mapD
    	fmt.Println(string(mapB
    
    	res1D := &response1{
    		Page:   1,
    		Fruits: []string{"apple", "peach", "pear"}}
    	res1B, _ := json.Marshal(res1D
    	fmt.Println(string(res1B
    
    	res2D := &response2{
    		Page:   1,
    		Fruits: []string{"apple", "peach", "pear"}}
    	res2B, _ := json.Marshal(res2D
    	fmt.Println(string(res2B
    
    	byt := []byte(`{"num":6.13,"strs":["a","b"]}`
    
    	var dat map[string]interface{}
    
    	if err := json.Unmarshal(byt, &dat; err != nil {
    		panic(err
    	}
    	fmt.Println(dat
    
    	num := dat["num"].(float64
    	fmt.Println(num
    
    	strs := dat["strs"].([]interface{}
    	str1 := strs[0].(string
    	fmt.Println(str1
    
    	str := `{"page": 1, "fruits": ["apple", "peach"]}`
    	res := response2{}
    	json.Unmarshal([]byte(str, &res
    	fmt.Println(res
    	fmt.Println(res.Fruits[0]
    
    	enc := json.NewEncoder(os.Stdout
    	d := map[string]int{"apple": 5, "lettuce": 7}
    	enc.Encode(d
    }
    

    XML

    package main
    
    import (
    	"encoding/xml"
    	"fmt"
    
    
    type Plant struct {
    	XMLName xml.Name `xml:"plant"`
    	Id      int      `xml:"id,attr"`
    	Name    string   `xml:"name"`
    	Origin  []string `xml:"origin"`
    }
    
    func (p Plant String( string {
    	return fmt.Sprintf("Plant id=%v, name=%v, origin=%v",
    		p.Id, p.Name, p.Origin
    }
    
    func main( {
    	coffee := &Plant{Id: 27, Name: "Coffee"}
    	coffee.Origin = []string{"Ethiopia", "Brazil"}
    
    	out, _ := xml.MarshalIndent(coffee, " ", "  "
    	fmt.Println(string(out
    
    	fmt.Println(xml.Header + string(out
    
    	var p Plant
    	if err := xml.Unmarshal(out, &p; err != nil {
    		panic(err
    	}
    	fmt.Println(p
    
    	tomato := &Plant{Id: 81, Name: "Tomato"}
    	tomato.Origin = []string{"Mexico", "California"}
    
    	type Nesting struct {
    		XMLName xml.Name `xml:"nesting"`
    		Plants  []*Plant `xml:"parent>child>plant"`
    	}
    
    	nesting := &Nesting{}
    	nesting.Plants = []*Plant{coffee, tomato}
    
    	out, _ = xml.MarshalIndent(nesting, " ", "  "
    	fmt.Println(string(out
    }
    

    时间-time

      GMT(Greenwich Mean Time):格林威治时间;GMT 根据地球的自转和公转来计算时间,它规定太阳每天经过位于英国伦敦郊区的皇家格林威治天文台的时间为中午12点;GMT 是前世界标准时。
    • UTC(Coordinated Universal Time),协调世界时间,又称世界统一时间;UTC 比 GMT 更精准,它根据原子钟来计算时间,适应现代社会的精确计时。在不需要精确到秒的情况下,可以认为 UTC=GMT;UTC 是现世界标准时。

    适应现代社会的精确计时从格林威治本初子午线起,往东为正,往西为负,全球共划分为 24 个标准时区,相邻时区相差一个小时;如何获取自Unix纪元以来的秒数、毫秒数或纳秒数和时间格式化。

    package main
    
    import (
    	"fmt"
    	"time"
    
    
    func main( {
    	p := fmt.Println
    
    	now := time.Now(
    	p(now
    
    	then := time.Date(
    		2009, 11, 17, 20, 34, 58, 651387237, time.UTC
    	p(then
    
    	p(then.Year(
    	p(then.Month(
    	p(then.Day(
    	p(then.Hour(
    	p(then.Minute(
    	p(then.Second(
    	p(then.Nanosecond(
    	p(then.Location(
    
    	p(then.Weekday(
    
    	p(then.Before(now
    	p(then.After(now
    	p(then.Equal(now
    
    	diff := now.Sub(then
    	p(diff
    
    	p(diff.Hours(
    	p(diff.Minutes(
    	p(diff.Seconds(
    	p(diff.Nanoseconds(
    
    	p(then.Add(diff
    	p(then.Add(-diff
    	p("-----------------------"
    	fmt.Println(now.Unix(
    	fmt.Println(now.UnixMilli(
    	fmt.Println(now.UnixNano(
    
    	fmt.Println(time.Unix(now.Unix(, 0
    	fmt.Println(time.Unix(0, now.UnixNano(
    	p("-----------------------"
    	t := time.Now(
    	p(t.Format(time.RFC3339
    
    	t1, e := time.Parse(
    		time.RFC3339,
    		"2012-11-01T22:08:41+00:00"
    	p(t1
    
    	p(t.Format("3:04PM"
    	p(t.Format("Mon Jan _2 15:04:05 2006"
    	p(t.Format("2006-01-02T15:04:05.999999-07:00"
    	form := "3 04 PM"
    	t2, e := time.Parse(form, "8 41 PM"
    	p(t2
    
    	fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n",
    		t.Year(, t.Month(, t.Day(,
    		t.Hour(, t.Minute(, t.Second(
    
    	ansic := "Mon Jan _2 15:04:05 2006"
    	_, e = time.Parse(ansic, "8:41PM"
    	p(e
    }
    

    网络-net

    URL

    url提供了一种统一的方式来定位资源,Go中解析url需要使用到其net包。

      URL格式:😕/:

      @:/:?#

    • scheme : 方案是如何访问指定资源的主要标识符,他会告诉负责解析 URL 应用程序应该使用什么协议;
    • user :用户名;
    • password :密码;
    • host : 主机组件标识了因特网上能够访问资源的宿主机器,可以有主机名或者是 IP 地址来表示;
    • port : 端口标识了服务器正在监听的网络端口。默认端口号是 80;
    • path : URL 的路径组件说明了资源位于服务器的什么地方;
    • params : URL 中通过协议参数来访问资源,比名值对列表,分号分割来进行访问;
    • query : 字符串是通过提问问题或进行查询来缩小请求资源类的范围;
    • frag : 为了引用部分资源或资源的一个片段,比如 URL 指定 HTML 文档中一个图片或一个小节;
    package main
    
    import (
        "fmt"
        "net"
        "net/url"
    
    
    func main( {
    
        s := "postgres://user:pass@host.com:5432/path?k=v#f"
    
        u, err := url.Parse(s
        if err != nil {
            panic(err
        }
    
        fmt.Println(u.Scheme
    
        fmt.Println(u.User
        fmt.Println(u.User.Username(
        p, _ := u.User.Password(
        fmt.Println(p
    
        fmt.Println(u.Host
        host, port, _ := net.SplitHostPort(u.Host
        fmt.Println(host
        fmt.Println(port
    
        fmt.Println(u.Path
        fmt.Println(u.Fragment
    
        fmt.Println(u.RawQuery
        m, _ := url.ParseQuery(u.RawQuery
        fmt.Println(m
        fmt.Println(m["k"][0]
    }
    

    HTTP客户端和服务端

      作为客户端发送http请求
    package main
    
    import (
        "bufio"
        "fmt"
        "net/http"
    
    
    func main( {
    
        resp, err := http.Get("https://gobyexample.com"
        if err != nil {
            panic(err
        }
        defer resp.Body.Close(
    
        fmt.Println("Response status:", resp.Status
    
        scanner := bufio.NewScanner(resp.Body
        for i := 0; scanner.Scan( && i < 5; i++ {
            fmt.Println(scanner.Text(
        }
    
        if err := scanner.Err(; err != nil {
            panic(err
        }
    }
    
      作为服务端监听HTTP请求
    package main
    
    import (
        "fmt"
        "net/http"
    
    
    func hello(w http.ResponseWriter, req *http.Request {
    
        fmt.Fprintf(w, "hello\n"
    }
    
    func headers(w http.ResponseWriter, req *http.Request {
    
        for name, headers := range req.Header {
            for _, h := range headers {
                fmt.Fprintf(w, "%v: %v\n", name, h
            }
        }
    }
    
    func main( {
    
        http.HandleFunc("/hello", hello
        http.HandleFunc("/headers", headers
    
        http.ListenAndServe(":8090", nil
    }
    

    访问测试页面:http://localhost:8090/hello和http://localhost:8090/headers

    加密

    package main
    
    import (
    	"crypto/md5"
    	"crypto/sha256"
    	"encoding/hex"
    	"fmt"
    
    
    func main( {
    	s := "sha256 this string"
    
    	h := sha256.New(
    
    	h.Write([]byte(s
    
    	bs := h.Sum(nil
    
    	fmt.Println(s
    	fmt.Printf("%x\n", bs
    
    	has := md5.New(
    	has.Write([]byte("abc123"
    	b := has.Sum(nil
    	fmt.Println(b
    	fmt.Println(hex.EncodeToString(b
    	fmt.Printf("%x", b
    
    	c := md5.Sum([]byte("abc123"
    	fmt.Printf("%x", c
    }
    

    IO操作

    读写文件

    读写文件在Go程序是常见的功能,bufio包实现了带缓冲区的读写,是对文件读写的封装.其中的读写文件在Go程序是常见的功能Go语言里使用io.Reader和io.Writer两个 interface 来抽象I/O。io.Reader 接口代表一个可以从中读取字节流的实体,而io.Writer则代表一个可以向其写入字节流的实体。io.Reader/Writer 常用的几种实现:

      net.Conn: 表示网络连接。
    • os.Stdin, os.Stdout, os.Stderr: 标准输入、输出和错误。
    • os.File: 网络,标准输入输出,文件的流读取。
    • strings.Reader: 字符串抽象成 io.Reader 的实现。
    • bytes.Reader: []byte抽象成 io.Reader 的实现。
    • bytes.Buffer: []byte抽象成 io.Reader 和 io.Writer 的实现。
    • bufio.Reader/Writer: 带缓冲的流读取和写入(比如按行读写)。
    package main
    
    import (
    	"bufio"
    	"fmt"
    	"io"
    	"os"
    
    
    func check(e error {
    	if e != nil {
    		panic(e
    	}
    }
    
    func main( {
    	writeDemo(
    	readDemo(
    }
    
    func writeDemo( {
    
    	d1 := []byte("hello\ngo\n"
    	err := os.WriteFile("/tmp/dat1", d1, 0644
    	check(err
    
    	f, err := os.Create("/tmp/dat2"
    	check(err
    
    	defer f.Close(
    
    	d2 := []byte{115, 111, 109, 101, 10}
    	n2, err := f.Write(d2
    	check(err
    	fmt.Printf("wrote %d bytes\n", n2
    
    	n3, err := f.WriteString("writes\n"
    	check(err
    	fmt.Printf("wrote %d bytes\n", n3
    
    	f.Sync(
    
    	w := bufio.NewWriter(f
    	n4, err := w.WriteString("buffered\n"
    	check(err
    	fmt.Printf("wrote %d bytes\n", n4
    
    	w.Flush(
    
    }
    func readDemo( {
    	dat, err := os.ReadFile("/tmp/dat1"
    	check(err
    	fmt.Print(string(dat
    
    	f, err := os.Open("/tmp/dat1"
    	check(err
    
    	b1 := make([]byte, 5
    	n1, err := f.Read(b1
    	check(err
    	fmt.Printf("%d bytes: %s\n", n1, string(b1[:n1]
    
    	o2, err := f.Seek(6, 0
    	check(err
    	b2 := make([]byte, 2
    	n2, err := f.Read(b2
    	check(err
    	fmt.Printf("%d bytes @ %d: ", n2, o2
    	fmt.Printf("%v\n", string(b2[:n2]
    
    	o3, err := f.Seek(6, 0
    	check(err
    	b3 := make([]byte, 2
    	n3, err := io.ReadAtLeast(f, b3, 2
    	check(err
    	fmt.Printf("%d bytes @ %d: %s\n", n3, o3, string(b3
    
    	_, err = f.Seek(0, 0
    	check(err
    
    	r4 := bufio.NewReader(f
    	b4, err := r4.Peek(5
    	check(err
    	fmt.Printf("5 bytes: %s\n", string(b4
    
    	f.Close(
    }
    

    环境变量

    package main
    
    import (
    	"fmt"
    	"os"
    	"strings"
    
    
    func main( {
    
    	os.Setenv("FOO", "1"
    	fmt.Println("FOO:", os.Getenv("FOO"
    	fmt.Println("BAR:", os.Getenv("BAR"
    
    	fmt.Println(
    	for _, e := range os.Environ( {
    		pair := strings.SplitN(e, "=", 2
    		fmt.Println(pair[0]
    	}
    }
    

    命令行

      命令行参数:程序执行参数化的常用方法。例如,运行hello。Go使用run和hello。Go程序的参数。
    package main
    
    import (
    	"fmt"
    	"os"
    
    
    func main( {
    
    	argsWithProg := os.Args
    	argsWithoutProg := os.Args[1:]
    
    	arg := os.Args[3]
    
    	fmt.Println(argsWithProg
    	fmt.Println(argsWithoutProg
    	fmt.Println(arg
    }
    
    go run demo.go a b c d
    [./demo.exe a b c d]
    [a b c d]
    c
    
      命令行标记:为命令行程序指定选项的常用方法。例如,在wc -l中,-l是命令行标志。
    package main
    
    import (
    	"flag"
    	"fmt"
    
    
    func main( {
    
    	wordPtr := flag.String("word", "foo", "a string"
    
    	numbPtr := flag.Int("numb", 42, "an int"
    	forkPtr := flag.Bool("fork", false, "a bool"
    
    	var svar string
    	flag.StringVar(&svar, "svar", "bar", "a string var"
    
    	flag.Parse(
    
    	fmt.Println("word:", *wordPtr
    	fmt.Println("numb:", *numbPtr
    	fmt.Println("fork:", *forkPtr
    	fmt.Println("svar:", svar
    	fmt.Println("tail:", flag.Args(
    }
    
    go run demo.go -word=opt -numb=7 -fork -svar=flag
    word: opt
    numb: 7
    fork: true
    svar: flag
    tail: []
    
      命令行子命令:一些命令行工具如go工具或git有许多子命令,每个子命令都有自己的一组标志;例如go build和go get是go工具的两个不同的子命令;flag包允许我们轻松地定义具有自己标志的简单子命令。
    package main
    
    import (
        "flag"
        "fmt"
        "os"
    
    
    func main( {
    
        fooCmd := flag.NewFlagSet("foo", flag.ExitOnError
        fooEnable := fooCmd.Bool("enable", false, "enable"
        fooName := fooCmd.String("name", "", "name"
    
        barCmd := flag.NewFlagSet("bar", flag.ExitOnError
        barLevel := barCmd.Int("level", 0, "level"
    
        if len(os.Args < 2 {
            fmt.Println("expected 'foo' or 'bar' subcommands"
            os.Exit(1
        }
    
        switch os.Args[1] {
    
        case "foo":
            fooCmd.Parse(os.Args[2:]
            fmt.Println("subcommand 'foo'"
            fmt.Println("  enable:", *fooEnable
            fmt.Println("  name:", *fooName
            fmt.Println("  tail:", fooCmd.Args(
        case "bar":
            barCmd.Parse(os.Args[2:]
            fmt.Println("subcommand 'bar'"
            fmt.Println("  level:", *barLevel
            fmt.Println("  tail:", barCmd.Args(
        default:
            fmt.Println("expected 'foo' or 'bar' subcommands"
            os.Exit(1
        }
    }
    
    go run demo.go foo -enable -name=joe a1 a2
    subcommand 'foo'
      enable: true
      name: joe
      tail: [a1 a2]
    

    数据库

    在Go中使用SQL或类SQL数据库通过database/sql包,它为面向行的数据库提供了一个轻量级接口;也即是在Go 的标准库中是没有数据库驱动,只提供了驱动接口,但有很多第三方实现了驱动,建议选择 go-sql-driver 这个实现是目前使用最多的,其github 地址是:https://github.com/go-sql-driver/mysql

    # 命令行安装三方库 
    go get github.com/go-sql-driver/mysql
    
    package main
    
    import (
    	"database/sql"
    	_ "github.com/go-sql-driver/mysql"
    	"log"
    
    
    func main( {
    	db, err := sql.Open("mysql", "root:123456@tcp(mysqlserver:3306/test"
    	if err != nil {
    		log.Fatal(err
    	}
    	defer db.Close(
    
    	var (
    		id   int
    		name string
    	
    	rows, err := db.Query("select id, name from test_data where id = ?", 1
    	if err != nil {
    		log.Fatal(err
    	}
    	defer rows.Close(
    	for rows.Next( {
    		err := rows.Scan(&id, &name
    		if err != nil {
    			log.Fatal(err
    		}
    		log.Println(id, name
    	}
    	err = rows.Err(
    	if err != nil {
    		log.Fatal(err
    	}
    }
    

    上面是匿名加载mysql驱动的,将它的包限定符别名为_,所以它导出的名称对我们的代码是不可见的;在底层,驱动程序将自己注册为database/sql包可用。

    排序-sort

    • 除了基本类型的排序,也可以对结构体进行排序。 结构体比基本类型更为复杂,排序时不能像数值和字符串一样拥有一些固定的单一原则;可以自定义排序接口,比如想要按自然顺序以外的方式对集合进行排序;例如希望按字符串的长度而不是按字母顺序排序。

    package main
    
    import (
    	"fmt"
    	"sort"
    
    
    type byLength []string
    
    func (s byLength Len( int {
    	return len(s
    }
    func (s byLength Swap(i, j int {
    	s[i], s[j] = s[j], s[i]
    }
    func (s byLength Less(i, j int bool {
    	return len(s[i] < len(s[j]
    }
    
    func main( {
    
    	strs := []string{"c", "a", "b"}
    	sort.Strings(strs
    	fmt.Println("Strings:", strs
    
    	ints := []int{7, 2, 4}
    	sort.Ints(ints
    	fmt.Println("Ints:   ", ints
    
    	s := sort.IntsAreSorted(ints
    	fmt.Println("Sorted: ", s
    
    	fruits := []string{"peach", "banana", "kiwi"}
    	sort.Sort(byLength(fruits
    	fmt.Println(fruits
    }
    

    测试和基准测试

    package main
    
    import (
        "fmt"
        "testing"
    
    
    func IntMin(a, b int int {
        if a < b {
            return a
        }
        return b
    }
    
    func TestIntMinBasic(t *testing.T {
        ans := IntMin(2, -2
        if ans != -2 {
            t.Errorf("IntMin(2, -2 = %d; want -2", ans
        }
    }
    
    func TestIntMinTableDriven(t *testing.T {
        var tests = []struct {
            a, b int
            want int
        }{
            {0, 1, 0},
            {1, 0, 0},
            {2, -2, -2},
            {0, -1, -1},
            {-1, 0, -1},
        }
    
        for _, tt := range tests {
    
            testname := fmt.Sprintf("%d,%d", tt.a, tt.b
            t.Run(testname, func(t *testing.T {
                ans := IntMin(tt.a, tt.b
                if ans != tt.want {
                    t.Errorf("got %d, want %d", ans, tt.want
                }
            }
        }
    }
    
    func BenchmarkIntMin(b *testing.B {
        for i := 0; i < b.N; i++ {
            IntMin(1, 2
        }
    }
    

    命令行执行go test -v

      本人博客网站IT小神 www.itxiaoshen.com

    编程笔记 » 云原生时代崛起的编程语言Go常用标准库实战

    赞同 (34) or 分享 (0)
    游客 发表我的评论   换个身份
    取消评论

    表情
    (0)个小伙伴在吐槽