标准库fmt
  • fmt.Fprintf 向文件中写内容
  • 格式化字符串
  • 获取标准输入,输入字段以空格分割
  • 获取标准输入,若用户输入包含空格,使用bufio实现

func main() {
	// fmt.Fprintf 向文件中写内容
	fileObj, err := os.OpenFile("./a.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		log.Fatal(err)
	}
	defer fileObj.Close()
	s := "text"
	fmt.Fprintf(fileObj, "%s\n", s)

	// 格式化字符串
	o := struct{ name string }{"zzdd"}
	fmt.Printf("%v\n", o)  // 值的默认格式
	fmt.Printf("%+v\n", o) // 同时输出字段名
	fmt.Printf("%#v\n", o) // 值的go语法
	fmt.Printf("%T\n", o)  // 值的类型
	fmt.Printf("100%%\n")  // 打印百分号

	// 获取标准输入,输入字段以空格分割
	// var (
	// 	name string
	// 	age  int
	// )
	// fmt.Print("please input your name and age: ")
	// fmt.Scan(&name, &age) // 注意这里的符号 &
	// fmt.Printf("name: %s age: %d\n", name, age)

	// 获取标准输入,若用户输入包含空格,使用bufio实现
	reader := bufio.NewReader(os.Stdin) // 从标准输入生成读对象
	fmt.Print("请输入: ")
	text, _ := reader.ReadString('\n') // 读到换行
	text = strings.TrimSpace(text)
	fmt.Printf("%#v\n", text)
}
/* 
========== 
{zzdd}
{name:zzdd}
struct { name string }{name:"zzdd"}
struct { name string }
100%
请输入: qq is good
"qq is good"
*/
标准库log
// 一个好的实践是将这部分通用配置放到init函数中
func init() {
	logFile, err := os.OpenFile("./a.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		log.Fatal(err)
		return
	}
	// 将日志写入文件
	log.SetOutput(logFile)
	// 控制输出日志信息的细节
	log.SetFlags(log.Lshortfile | log.Lmicroseconds | log.Ldate)
	// 配置日志信息前缀
	log.SetPrefix("[prefix_name] ")
}

func main() {
	// log.New 可以自定义日志输出
	// func New(out io.Writer, prefix string, flag int) *Logger
	logger := log.New(os.Stdout, "[prefix New] ", log.Lshortfile|log.Ldate|log.Ltime)
	logger.Println("logger log")
	log.Println("i am log")
	v := "this is log"
	log.Printf("%s", v)
	// log.Fatalln("fatal") // Fatalln会在写入日志后调用os.Exit(1)
	/*
		[prefix New] 2021/03/16 09:57:35 main.go:27: logger log
		cat a.log
		[prefix_name] 2021/03/16 10:00:25.470469 main.go:28: i am log
		[prefix_name] 2021/03/16 10:00:25.470494 main.go:30: this is log
	*/
}

标准库time

时间类型输出
unix时间戳
定时器
格式化时间(Go的诞生时间2006年1月2号15点04分)

package main

import (
	"fmt"
	"time"
)

func main() {
	// 时间类型
	now := time.Now()    // 当前时间
	year := now.Year()   // 当前年
	month := now.Month() // 当前月
	day := now.Day()
	fmt.Println(now)
	fmt.Printf("%d-%d-%d\n", year, month, day)
	timestamp := now.Unix() // 当前unix时间戳
	fmt.Printf("%v\n", timestamp)

	// 时间戳
	timeObj := time.Unix(timestamp, 0) // 将unix时间戳转换为时间
	fmt.Println(timeObj)
	hour := timeObj.Hour()     //时
	minute := timeObj.Minute() //分
	second := timeObj.Second() //秒
	fmt.Printf("%d:%d:%d\n", hour, minute, second)

	// 定时器
	// ticker := time.Tick(time.Second) // 间隔1秒
	// for i := range ticker {
	// 	fmt.Println(i)
	// }
	// 格式化时间,按照Go的诞生时间2006年1月2号15点04分
	// 24小时制
	fmt.Println(now.Format("2006-01-02 15:04:05.000 Mon Jan"))
	// 12小时制
	fmt.Println(now.Format("2006-01-02 03:04:05.000 PM Mon Jan"))
}
/*
========================
2021-03-15 18:18:32.977383 +0800 CST m=+0.000065185
2021-3-15
1615803512
2021-03-15 18:18:32 +0800 CST
18:18:32
2021-03-15 18:18:32.977 Mon Mar
2021-03-15 06:18:32.977 PM Mon Mar
*/
标准库strconv

strconv实现了基本数据类型和其字符串表示的相互转换。

  • int类型转化为string类型
  • str类型转化为int类型
  • Parse函数:转换字符串为给定类型的值
  • Format函数:将给定类型数据格式化为string类型
func main() {
	// int类型转化为string类型
	var i int = 4
	var itostr string = strconv.Itoa(i)
	fmt.Println(reflect.TypeOf(itostr), itostr)

	// str类型转化为int类型
	var str string = "5"
	strtoi, err := strconv.Atoi(str)
	if err != nil {
		fmt.Println("convert failed")
	}
	fmt.Println(reflect.TypeOf(strtoi), strtoi)

	// Parse函数用于转换字符串为给定类型的值
	b1, err := strconv.ParseBool("true")
	f1, err := strconv.ParseFloat("3.141", 64)
	i1, err := strconv.ParseInt("-2", 10, 64)
	u1, err := strconv.ParseUint("2", 10, 64)
	fmt.Println(reflect.TypeOf(b1), b1)
	fmt.Println(reflect.TypeOf(f1), f1)
	fmt.Println(reflect.TypeOf(i1), i1)
	fmt.Println(reflect.TypeOf(u1), u1)

	//Format函数实现了将给定类型数据格式化为string类型数据的功能
	s1 := strconv.FormatBool(true)
	s2 := strconv.FormatFloat(3.1415, 'E', -1, 64)
	s3 := strconv.FormatInt(-2, 16)
	s4 := strconv.FormatUint(2, 16)
	fmt.Println(reflect.TypeOf(s1), s1)
	fmt.Println(reflect.TypeOf(s2), s2)
	fmt.Println(reflect.TypeOf(s3), s3)
	fmt.Println(reflect.TypeOf(s4), s4)

}
/*
string 4
int 5
bool
string true
bool true
float64 3.141
int64 -2
uint64 2
string true
string 3.1415E+00
string -2
string 2
*/
}
标准库 testing

单元测试

约定1:与测试的代码在同级目录,并以 “文件名_test.go” 命名
约定2:测试函数以Test开头
约定3:got want模式,有助于快速发现失败的原因

简单测试

a.go

func Greeting(s string) string {
	return ("hello " + s)
}

a_test.go

func TestGreeting(t *testing.T) { // TestGreeting因为是Test开头,表明是一个测试,类型T包含很多用于测试代码的函数
	got := Greeting("zzd") // got表示要测试的值
	want := "hello zzd" //  want表示期望的值
	if got != want {
		t.Fatalf("expected %v, got %v", want, got) // 错误友情提示
	}
}
/*
终端执行
go test,显示测试结果,若将want内容修改为其它,则会打印错误友情提示
PASS
ok      06      0.017s
*/

单元测试覆盖率统计

go test -cover

PASS
coverage: 33.3% of statements
ok      06      0.017s

表格驱动测试

// 定义转化函数,匹配输入
func translate(s string) string {
	switch s {
	case "zh-gz":
		return "hello "
	case "zh-bj":
		return "hi "
	case "zh-sh":
		return "good "
	default:
		return "hello "
	}
}

// 定义got拼接
func Greeting(name, locale string) string {
	salutation := translate(locale)
	return (salutation + name)
}

// 使用表格驱动测试,能够同时测试很多条件
type GreetingTest struct {
	name   string
	locale string
	want   string
}

// 表格数据赋值
var greetingTests = []GreetingTest{
	{"aaa", "zh-gz", "hello aaa"},
	{"ddd", "zh-bj", "hi ddd"},
	{"ccc", "zh-sh", "good ccc"},
}

func TestGreeting(t *testing.T) { // TestGreeting因为是Test开头,表明是一个测试,类型T包含很多用于测试代码的函数
	for _, test := range greetingTests {
		got := Greeting(test.name, test.locale)
		if got != test.want {
			t.Errorf("Greeting(%s,%s)=%v;want %v", test.name, test.locale, got, test.want)
		}
	}
}
/*
go test
PASS
ok      06      0.017s
*/

性能(基准)测试

package temp

import (
	"bytes"
	"strings"
	"testing"
)

// 字符串拼接几种方法性能(基准)测试,
// 1、直接赋值
func StringAssign(j int) string {
	var s string
	for i := 0; i < j; i++ {
		s += "a"
	}
	return s
}

// 2、使用join赋值
func StringAppend(j int) string {
	s := []string{}
	for i := 0; i < j; i++ {
		s = append(s, "a")
	}
	return strings.Join(s, "")
}

// 3、使用缓冲区赋值
func StringBuffer(j int) string {
	var buffer bytes.Buffer
	for i := 0; i < j; i++ {
		buffer.WriteString("a")
	}
	return buffer.String()
}

// 性能(基准)测试需要以Benchmark打头,接受一个类型为B的参数,并对函数进行基准测试
func BenchmarkStringAssign(b *testing.B) {
	for i := 0; i < b.N; i++ {
		StringAssign(100)
	}
}

func BenchmarkStringAppend(b *testing.B) {
	for i := 0; i < b.N; i++ {
		StringAppend(100)
	}
}

func BenchmarkStringBuffer(b *testing.B) {
	for i := 0; i < b.N; i++ {
		StringBuffer(100)
	}
}

/*
//终端执行,结论:缓冲区速度最快
go test -bench=.

BenchmarkStringAssign-12          284379              3896 ns/op
BenchmarkStringAppend-12          558100              1974 ns/op
BenchmarkStringBuffer-12         1902393               632 ns/op
PASS
ok      06      4.138s
*/
标准库 os

文件操作

// 将日志写入文件
	f, err := os.OpenFile("stdout.log", os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()  // defer延时关闭文件
	log.SetOutput(f) // 通过SetOutput可以将标准输出直接输出到文件
	var count = 5
	for i := 0; i < count; i++ {
		log.Printf("log iteration %d", i)
	}

ioutil包用于执行一些常见的文件处理操作,底层使用os包,复杂操作可以用os包


/*
*/

type Config struct {
	Name string  `json:name`
	Age  float64 `json:age`
	God  bool    `json:god`
}

func main() {
	// 读取文件
	fileBytes, err := ioutil.ReadFile("stdout.log") // 返回一个字节切片
	if err != nil {
		log.Fatal(err)
	}
	fileString := string(fileBytes) // 将字节切片转换为字符串
	fmt.Println(fileString)
	// 创建文件
	b := make([]byte, 0) // WriteFile需接受字节切片,创建一个,并给文件赋权
	err1 := ioutil.WriteFile("err.log", b, 0644)
	if err1 != nil {
		log.Fatal(err1)
	}
	// 将文本写入文件,文件不存在则创建
	s := "hello world"
	err2 := ioutil.WriteFile("err1.log", []byte(s), 0644)
	if err != nil {
		log.Fatal(err2)
	}
	// 列出当前目录内容,ReadDir返回列表,包含Name、Size等
	files, err3 := ioutil.ReadDir(".")
	if err3 != nil {
		log.Fatal(err3)
	}
	for _, file := range files {
		fmt.Println(file.Name(), file.Size(), file.IsDir(), file.Mode(), file.ModTime())
	}
	// 复制文件,使用os
	from, err := os.Open("err1.log") // 读取文件
	if err != nil {
		log.Fatal(err)
	}
	defer from.Close() // 一定不要忘记关闭文件

	to, err := os.OpenFile("err1.copy", os.O_RDWR|os.O_CREATE, 0666) // 打开文件
	if err != nil {
		log.Fatal(err)
	}
	defer to.Close() // 一定不要忘记关闭文件

	_, err = io.Copy(to, from) // io.Copy(目标,来源)
	if err != nil {
		log.Fatal(err)
	}
	// 删除文件,需要先判断是否存在
	// err5 := os.Remove("./err.log")
	// if err5 != nil {
	// 	log.Fatal(err5)
	// }
	// 从json文件中读取配置
	f, err := ioutil.ReadFile("config.json")
	if err != nil {
		log.Fatal(err)
	}
	c := Config{}
	err = json.Unmarshal(f, &c) // json解码
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%+v\n", c.Name)

}

标准库 flag

简单命令行传参

func main() {
	
	// 1.获取命令行参数os.Args
	// for i, arg := range os.Args {
	// 	fmt.Println("arg:", i, arg)
	// }
	
	// 2.获取命令行参数使用flag包
	// flag.Usage自定义帮助文本
	flag.Usage = func() {
		usageText := `Usage cli [OPTION]
		An example of customizing usage output
		-s, --s		string help text
		-i, --i		int help text
		-b, --b		bool help text
		`
		fmt.Fprintln(os.Stderr, usageText)

	}
	// flag.String表示接收string类型参数
	s := flag.String("s", "hi", "string help text")
	i := flag.Int("i", 1, "int help text")
	b := flag.Bool("b", false, "bool help text")
	//flag.Parse 传递声明的参数
	flag.Parse()
	fmt.Println("value of s:", *s)
	fmt.Println("value of i:", *i)
	fmt.Println("value of b:", *b)
}

复杂命令行参数(子命令)

func flagUsage() {
	usageText := `script is a string handle cli tool.
Usage:
./script command [arguments]
The commands are:
	upper 
	lower
Use "./script [command] --help" for more information about a command.
	`
	fmt.Fprintf(os.Stderr, "%s\n", usageText)
}

func main() {
	// flag.Usage自定义帮助文本
	flag.Usage = flagUsage
	// 添加子命令flag.NewFlagSet
	upperCmd := flag.NewFlagSet("upper", flag.ExitOnError)
	lowerCmd := flag.NewFlagSet("lower", flag.ExitOnError)
	// 当参数数量为1时,打印帮助文本
	if len(os.Args) == 1 {
		flag.Usage()
		return
	}
	switch os.Args[1] {
	case "upper": // 第一个参数为upper,若未指定-s,默认为空字符串
		s := upperCmd.String("s", "", "to be upperd")
		upperCmd.Parse(os.Args[2:])
		fmt.Println(strings.ToUpper(*s))
	case "lower":
		s := lowerCmd.String("s", "", "to be lowerd")
		lowerCmd.Parse(os.Args[2:])
		fmt.Println(strings.ToLower(*s))
	default:
		flag.Usage() // 啥也不输入打印帮助信息
	}

}
net/http

http服务端

// w r 意味着可查看或操作请求,再将响应返回给客户端,w生成响应
func greet(w http.ResponseWriter, r *http.Request) {
	fmt.Println(r.Header.Get("Accept"), r.Method)
	w.Header().Set("my-header", "i am setting a header")              // 设置响应报头           // 设置自定义header
	w.Header().Set("Content-Type", "application/json; charset=utf-8") // 同理,修改header直接覆盖就好
	// fmt.Fprintf(w, "Hello World! %s", time.Now())
	// 根据请求类型,进行不同操作
	switch r.Header.Get("Accept") {
	case "application/json":
		fmt.Fprintf(w, "json")
	case "application/xml":
		fmt.Fprintf(w, "xml")
	default:
		fmt.Fprintf(w, "default")
	}
}
func users(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "users! %s")
}

func main() {
	http.HandleFunc("/", greet) // 路由信息处理
	http.HandleFunc("/users/", users)
	http.ListenAndServe(":8080", nil) // server监听配置
}

http客户端

func main() {
	// 带参数的get请求
	apiUrl := "https://www.baidu.com/"
	// URL param
	data := url.Values{}
	data.Set("name", "zzd")
	data.Set("age", "18")
	u, err := url.ParseRequestURI(apiUrl)
	if err != nil {
		log.Fatal(err)
	}
	u.RawQuery = data.Encode() // URL encode 拼接字符串
	fmt.Println(u.String())
	resp, err := http.Get(u.String()) // 发送get请求
	if err != nil {
		log.Fatal(err)
		return
	}
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
		return
	}
	fmt.Println(string(b))

}

func main() {
	// 发送post请求
	postData := strings.NewReader(`{"some":"json"}`)
	res, err := http.Post("http://127.0.0.1:8080", "application/json", postData)
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", body)
func main() {
	// 通过transport细粒度控制超时,http连接的各个阶段
	tr := &http.Transport{
		DialContext: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
		}).DialContext,
		TLSHandshakeTimeout:   10 * time.Second,
		IdleConnTimeout:       90 * time.Second,
		ResponseHeaderTimeout: 10 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	}
	// 自定义客户端请求信息client.Do()
	/*
		设置报头、基本身份认证、cookie信息、发起其它方式的 HTTP 请求,比如 PUT、PATCH、DELETE 等
	*/
	debug := os.Getenv("DEBUG") // 读取环境变量

	client := &http.Client{
		Timeout:   1 * time.Second, // Timeout设置请求超时时间1s
		Transport: tr,              // Transport细粒度控制超时
	}
	request, err := http.NewRequest("GET", "http://127.0.0.1:8080", nil)
	request.Header.Add("client-header", "i am client header") // 自定义client header

	if err != nil {
		log.Fatal(err)
	}
	if debug == "1" {
		debugRequest, err := httputil.DumpRequestOut(request, true) //调试http显示请求信息
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("%s", debugRequest)
	}
	response, err := client.Do(request) // 自定义请求信息
	
	defer response.Body.Close()

	if debug == "1" {
		debugResponse, err := httputil.DumpResponse(response, true) // 调试http显示响应报头信息
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("%s", debugResponse)
	}
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", body)
}
/*
# go run main.go

GET / HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Go-http-client/1.1
Client-Header: i am client header // 客户端发起的自定义请求报头
Accept-Encoding: gzip

HTTP/1.1 200 OK
Content-Length: 7
Content-Type: application/json; charset=utf-8
Date: Mon, 15 Mar 2021 01:22:40 GMT
My-Header: i am setting a header // 服务端返回的自定义响应报头
*/
json编码解码

使用encoding/json中Marshal和Unmarshal
json编码和解码必须创建结构体,这样可以让代码更健壮,容错能力更强
json与go数据类型对应关系如下,因为go是强类型,需要做转换

jsongo
Booleanbool
Numberfloat64
Stringstring
Array[]interface{}
Objectmap[string]interface{}
Nullnil
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
)

// 使用encoding/json中Marshal和Unmarshal
// json编码和解码必须创建结构体,这样可以让代码更健壮,容错能力更强
type Person struct {
	Name    string   `json:"name,omitempty"` // ``代表标签,Name重命名为name
	Age     int      `json:"age,omitempty"`
	Hobbies []string `json:"hobbies,omitempty"` // omitempty忽略零值,零值则不显示该字段
}
// 定义api返回数据的结构体
type User struct {
	Name      string `json:"name"`
	Blog      string `json:"blog"`
	SiteAdmin bool   `json:site_admin`
}

func main() {
	// 使用Marshal编码json
	p := Person{
		Name:    "zzd",
		Age:     18,
		Hobbies: []string{"basketball", "cheese"},
	}
	jsonByteData, err := json.Marshal(p) // 1. 编码成json byte
	if err != nil {
		log.Fatal(err)
	}
	jsonStringData := string(jsonByteData) // 2. 转化为string
	fmt.Println("encode json:", jsonStringData)

	// 使用Unmarshal解码json
	jsonStringData1 := `{"name":"zzz", "age": 20, "hobbies":["ball", "cheese"]}`
	jsonByteData1 := []byte(jsonStringData1)
	p1 := Person{}
	err1 := json.Unmarshal(jsonByteData1, &p1)
	if err1 != nil {
		log.Fatal(err1)
	}
	fmt.Printf("uncode json解码:%+v\n", p1)

	// 处理http收到的json
	var u User
	res, err := http.Get("https://api.github.com/users/shapeshed")
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()
	// fmt.Println(res)
	err = json.NewDecoder(res.Body).Decode(&u) // 将数据流解码为结构体
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%+v\n", u)
}

标准库math/rand

生成随机数

func random() {
	rand.Seed(time.Now().UnixNano()) // 通过Seed获取时间戳,生成随机数
	for i := 0; i < 5; i++ {
		r := rand.Intn(10) // 10以内的随机数
		fmt.Println(r, 0-r)
	}

}
func main() {
	random()
}