Golang~~~有料才能 够浪

^_^ math

// 上下取整
math.Ceil(3.14) // 4
math.Floor(3.14) // 3

// golang没有类似python的round()函数,脑洞:先+0.5,然后向下取整!
func round(x float64) int {
	return int(math.Floor(x + 0.5))
}
// 四舍五入到小数点 后 n 位
func RoundFloat(f float64, n int) float64 {
	n10 := math.Pow10(n)
	return math.Trunc((f+0.5/n10)*n10) / n10
}

// 分解小数
a,b := math.Modf(3.14)   // a=3 b=0.1400000...0001

// 获取整数位
res := math.Trunc(3.5415) // 3
// 自己试出来的语法糖:
var a float64 = 3.5415
int(a) // ==> 3

// 绝对值
math.Abs(-8) // 8

// 幂运算
math.Pow(5,3) // 125
math.Sqrt(125) // 5
math.Cqrt(25) // 5

// 三角函数
math.Sin(math.PI / 2) // 1

// 20以内的随机数
rand.Seed(time.Now().UnixNano())
res := rand.Intn(20)

说明:
为了保证方法的通用性,大部分方法的 参数 和 返回值 都是 float64 类型的。


^_^ string

var s string = "abcd-abcd,你好"

strings.Repeat(s, 2) 	// "abcd-abcd,你好abcd-abcd,你好"
var s string = "+abcd+"

strings.Trim("+") 		// "abcd"
strings.TrimRight("+") 		// "+abcd"
strings.TrimLeft("+") 		// "abcd+"
var s string = "abcd-abcd,你好"

strings.Count(s, "ab") 		// 2

strings.HasPrefix(s, "a")		 // true
strings.HasSuffix(s, "你好") 		// true
strings.Contains(s,"d-a")		 // true
strings.ContainsAny(s,"老铁你好")		 // true

strings.Index(s, "cd")		 // 2
strings.LastIndex(s, "cd") 		// 7

strings.EqualFold("aBc", "abc") 		// 忽略大小写:true
"aBc" == "abc"		 // 不忽略大小写:false

var s string = "abcd-abcd,你好"

strings.Split(s, "c")		 // []string {"ab", "d-ab", "d,你好"}
strings.SplitAfter(s, "c")		 // []string {"abc", "d-abc", "d,你好"}
// Join 反向操作
var q = []string{"a", "b", "c"}
strings.Join(q, "")		 // abc
strings.Join(q, "-")		 // a-b-c

strings.ToUpper(s) 		// "ABCD-ABCD,你好"
strings.ToLower(s)
strings.Title("aaa bbb") 		// Aaa Bbb

strings.Replace("a-b-c", "-", "+", 1)		 // "a+b-c"
strings.Replace("a-b-c", "-", "+", -1)		 // "a+b+c"

^_^ strconv

  • bool
// 除了字符串: "1", "t", "true" (字母不区分大小写),其他均为false
strconv.ParseBool("yse") // false

strconv.FormatBool(true) // "true"
  • int64
// 参2:进制;  参3:随便
strconv.ParseInt("11", 10, 64) 		// int64: 11

strconv.FormatInt(int64(11), 10) 		// "11"
  • int
// 字符串 转 整数 数字 的快捷方式
var str string = "100" // str 必须是整数
strconv.Atoi(str)  // int: 100
  • float64
strconv.ParseFloat("3.14", 64) 		// float64: 3.14

// 参2:格式标记; 参3:小数点后保留位数  参4:格式化的float类型 32 or 64
strconv.FormatFloat(3.14, 'f', 4, 64)

说明:
Parse => 字符串—转化—>别的类型, 返回 两个值
Format => 别的类型—转化—>字符串, 返回 一个值


^_^ regexp

  • 元字符

. : 匹配所有字符

\w : 数字和字母
\W : 非 数字和字母 (±=)

\d : 数字
\D : 非 数字

\s : 空白字符
\S : 非 空白字符

[ ]: 字符集合
[a-zA-Z0-9] ===》 所有 大小写字母 和 数字
[\u4e00-\u9fa5] ===》 所有汉字 (从 “一”到 ”龥”)
[^0-9] ===》 集合中的 ^ 范围取反: 除数字以外的所有字符

  • 限定符

^ : 开头位置限定符
$ : 结束位置限定符

? + * : 重复限定符
x* ===》 匹配零个或多个 x,优先匹配更多(贪婪模式: 倾向于多的)
x+ ===》 匹配一个或多个 x,优先匹配更多(贪婪)
x? ===》 匹配零个或一个 x,优先匹配一个(贪婪)
x{n,m} ===》 匹配 n 到 m 个 x,优先匹配更多(贪婪)
x{n,} ===》 匹配 n 个或多个 x,优先匹配更多(贪婪)
x{n} ===》 只匹配 n 个 x
后加?改变贪婪模式 为 非贪婪模式:
x*? ===》 匹配零个或多个 x,优先匹配更少(非贪婪模式: 倾向于少的)
x+? ===》 匹配一个或多个 x,优先匹配更少(非贪婪)
x?? ===》 匹配零个或一个 x,优先匹配零个(非贪婪)
x{n,m}? ===》 匹配 n 到 m 个 x,优先匹配更少(非贪婪)
x{n,}? ===》 匹配 n 个或多个 x,优先匹配更少(非贪婪)
x{n}? ===》 只匹配 n 个 x

{} : 次数限定符
x{3} => 3个x; x{3,8} 至少3个 ,最多8个

  • 正则应用
var s string = "111ww222ww333"

// 定义一个 正则变量
reg := regexp.MustCompile(`[\d]+`)

reg.FindString(s) //111
reg.FindAllString(s, 2) // [111 222]
reg.FindAllString(s, -1) //[111 222 333]
reg.MatchString(s) //true

^_^ 自定义 切片 相关方法

func push(arr []int, item int) []int {
	return append(arr, item)
}

func pop(arr []int) []int {
	l := len(arr)
	if l > 0 {
		return arr[0 : l-1]
	} else {
		return arr
	}
}

func addByIndex(arr []int, item int, index int) []int {
	l := len(arr)
	if index <= l && index >= 0 {
		before := arr[:index]
		after := arr[index:]
		tmp := append([]int{}, before...)
		tmp = append(tmp, item)
		return append(tmp, after...)
	}
	return arr
}

func delByIndex(arr []int, index int) []int {
	l := len(arr)
	if index <= l-1 && index >= 0 {
		return append(arr[:index], arr[index+1:]...)
	}
	return arr
}

func delByValue(arr []int, value int) []int {
	for i, v := range arr {
		if v == value {
			return append(arr[:i], arr[i+1:]...)
		}
	}
	return arr
}

^_^ function

默认值参数

go中没有 默认值参数, 但是我可以实现 默认值参数的 功能:

package main

import (
	"fmt"
	"strconv"
	"strings"
)

//  自定义 默认参数 的 结构体
type Arr struct {
	// 这里用 字符串的好处是 可以 方便 转换为其他的类型,
	// 这就是的 默认值参数 的 类型 范围更广
	ctx string
}

func (that *Arr) Change(ctx string) {
	that.ctx = ctx
}

// 实现 默认值参数 的函数
func aaa(generalArr int, ctx ...string) {
	// 定义 3 个 默认值参数
	name := Arr{
		ctx: "tom", // 设置默认值
	}
	age := Arr{
		ctx: "10",
	}
	sex := Arr{
		ctx: "man",
	}

    // 这是核心:
	// 按照 默认值参数 的 名称 , 给 默认值参数 对应赋值
	for _, v := range ctx {
		key := strings.Trim(strings.Split(v, "=")[0], " ")
		val := strings.Trim(strings.Split(v, "=")[1], " ")
		switch key {
		case "name":
			name.Change(val)
		case "age":
			age.Change(val)
		case "sex":
			sex.Change(val)
		default:
			return
		}
	}
	// 普通参数
	fmt.Println("普通参数:", generalArr)
	ageInt, _ := strconv.Atoi(age.ctx)
	// 默认值参数
	fmt.Println("默认值参数: name:", name.ctx, "-----age:", ageInt, "-----sex:", sex.ctx)
}

func main() {
	aaa(123)                                       //name: tom -----age: 10 -----sex: man
	aaa(123, "name = cat", "sex=110", "age = 789") // name: cat -----age: 110 -----sex: man
}

^_^ time

  • 时间段
// 1.官方时间段
const (
    Nanosecond  Duration = 1 								 //纳秒(参考最底层)
    Microsecond          = 1000 * Nanosecond 	 // 微秒
    Millisecond          = 1000 * Microsecond 		// 毫秒
    Second               = 1000 * Millisecond 			// 秒
    Minute               = 60 * Second							// 分
    Hour                 = 60 * Minute 								// 时
)
time.Sleep(time.Second * 5)

// 2.生成时间段
duration := time.ParseDuration("3600s") 	// 单位: h、m、s、ms、us、ns
time.Sleep(duration)

//换算:
duration.Hours()		 // 1
duration.Minutes() 		// 60
duration.Seconds()		 // 3600
duration.Milliseconds() 		// 3600000
  • 时间点
// 获取 时间 结构体
Tm := time.Now() 		//struct: 2020-02-22 22:22:22.169010574 +0800 CST m=+0.000046516

Tm.Format("2006/01/02 15:04:05") 		// string: 2020/02/22 22:22:22

Tm.Unix() 		// 单位为 秒 的 时间戳
Tm.UnixNano()		 // 单位为 纳秒 的 时间戳

Tm.Year() 		// 2020
Tm.Month()		 // February
int(Tm.Month())		 // 2
Tm.Day() 		// 22
Tm.Hour() 		// 22
Tm.Minute()		 // 22
Tm.Second() 		// 22
  • 特定 时间点
// 两个小时之前的时间
time.Now().Add(-2 * time.Hour).Format("2006/01/02 15:04:05")

// 两个小时之后的时间
time.Now().Add(2 * time.Hour).Format("2006/01/02 15:04:05")

// 指定时间点
timeStand := "2006/01/02 15:04:05"
timeStr := "2020/08/08 10:10:10"
area,_ := time.LoadLocation("Asia/Shanghai") // Asia/Shanghai 不能写错,区分大小写
Tm,_ := time.ParseInLocation(timeStand, timeStr, area)

// 指定时间点(2)
time.Date(2020,08,08,10,10,10,0, time.Local)
  • 时戳互转
// 时 --转--> 戳
timeStamp := time.Now().Unix()

// 戳 --转--> 时
Tm := time.Unix(timeStamp, 0)		 // 参数1:时间戳; 参数2:0-9亿内任意数
  • 间隔计算
// 计算 时间间隔
start := time.Now()
    time.Sleep(time.Second * 2)
duration := time.Since(start)
    fmt.Println(duration) // 2.000336177s

// 计算 日期间隔
wtt := time.Date(1993, 7, 28, 12, 30, 6, 100, time.Local)
zqq := time.Date(1994, 10, 22, 10, 00, 00, 100, time.Local)
  // 时间早的 作为参数,时间晚的 调用方法
res := zqq.Sub(wtt) // 10821h29m54s

// 如果计算 现在时间  到目标时间 的 数据距离,可以用Sub方法,如下:
	aimTime := time.Now().Add(30 * time.Minute)
	res := aimTime.Sub(time.Now()).Seconds() // 警告: should use time.Until instead of t.Sub(time.Now())
	fmt.Println(res)

// golang的 包中的 Until方法,是Sub计算现在时间  到目标时间 的 数据距离 的快捷方法,
// 所以上面报了那样的警告,为了移除警告,我们这样做:
	aimTime := time.Now().Add(30 * time.Minute)
	RES := time.Until(aimTime).Seconds() //得到秒数,建议用 int() 取整
	fmt.Println(RES)
	
说明: 如果计算 现在的时间 距离 过去的时间,那么得到的是负数
  • 世界统一时间UTC

世界的每个地区都有自己的本地时间,在Internet及无线电通信时,有一个统一的时间是非常重要的!
整个地球分为二十四时区,每个时区都有自己的本地时间。
在国际无线电通信中,为统一而普遍使用一个标准时间,称为通用协调时(UTC, Universal Time Coordinated)。
格林尼治 的当地时间 称之为GMT(Greenwich Mean Time), UTC 在时间值上 采用 了 GMT时间。
但要区分, UTC是属于世界的,而GMT是属于格林尼治 当地的
CST 是中国的当地时间(China Standard Time UT+8:00)
CST 是古巴的当地时间(Cuba Standard Time UT-4:00)
CST 是美国中部的当地时间(Central Standard Time (USA) UT-6:00)
CST 是澳大利亚中部的当地时间(Central Standard Time (Australia) UT+9:30)
LON 是伦敦的当地时间
JRS 耶路撒冷(Jerusalem)以色列和巴勒斯坦的当地时间,等等

	// 世界所有电脑的统一时间 :UTC 时间
	time.Now().UTC().Format("2006-01-02 15:04:05") // 2021-08-03 08:12:07
	// 当地时间
	time.Now().Local().Format("2006-01-02 15:04:05") // 2021-08-03 16:12:07
	// 默认 获取的就是 当地时间
	time.Now().Format("2006-01-02 15:04:05") // 2021-08-03 16:12:07

	// 重点:  go 的 --时间体-- 的表现时间的形式:   时间值   +   时区   +   字母缩写   +   [ 其他 ]
	北京 := time.Now().Local()          // 2021-08-03 16:56:42.944422723    +0800    CST
	世界标准 := time.Now().UTC()   // 2021-08-03 08:56:42.944422915    +0000    UTC
  • 世界各地时间
// 纽约时间
	北京时间 := time.Now()
	fmt.Println(北京时间) // 2021-08-03 17:26:35  +0800  CST 

	local, _ := time.LoadLocation("America/New_York") // 参数 时区标志
	// 和 当地现在 时间值 一样的 纽约时间 (不一定是 纽约人 正在经历的时间,除非纽约 和 中国 一个时区)
	t, _ := time.ParseInLocation("2006-01-02 15:04:05", time.Now().Format("2006-01-02 15:04:05"), local)
	fmt.Println(t)  //   2021-08-03 17:26:35 -0400 EDT
	fmt.Println(t.Zone())  // EDT
	 // 和 当地现在 时间值 对应的 纽约时间 (此时此刻北京本地时间 对应的 纽约的当地时间, 纽约人正在经历的时间)
	NY := t.Local()
	fmt.Println(NY) //  2021-08-04 05:26:35 +0800 CST

//耶路撒冷时间
	北京时间 := time.Now()
	fmt.Println(北京时间) // 2021-08-03 17:32:37 CST m=+0.000051113

	local, _ := time.LoadLocation("Asia/Jerusalem")
	t, _ := time.ParseInLocation("2006-01-02 15:04:05", time.Now().Format("2006-01-02 15:04:05"), local)
	fmt.Println(t) 		 // 2021-08-03 17:32:37 +0300 IDT
	fmt.Println(t.Zone())  // IDT
	YLSL := t.Local()
	fmt.Println(YLSL) 	// 2021-08-03 22:32:37 +0800 CST
  • 通过 UTC 和 时区 计算 世界各地时间

公式: UTC + 时区差=本地时间
时区差东为正,西为负;东八区 比UTC 快个小时,故而记为: +0800,
如果快12个小时零45 分钟 则记为: +1245。

1. 假设 UTC 时间为:  2021-08-03 08:56:42, 则记为: 0856
北京时间 则为: 0856 ++0800=1656  ==> 2021-08-03 16:56:42

纽约 是 西五区,记为: -0500
纽约时间则为: 0856+-0500=0356   ==> 2021-08-03 03:56:42



2.  以上运算的结果都是 正数, 如果出现负数,则如下操作:
若结果是负数就意味着是UTC前一天(即昨天),
把这个负数加上2400就是UTC在前一天的时间。
例如,本地(北京)时间是 0325 (凌晨325分),那么,UTC就是 0325 - 0800 = -0475,
负号意味着是前一天, -0475 + 2400 = 1925,既前一天的晚上725分。

^_^ runtime

golang 的 runtime 在 golang 中的地位类似于 Java 的虚拟机,不过 go runtime 不是虚拟机.
golang 程序生成可执行文件在指定平台上即可运行,效率很高, 它和 c/c++ 一样编译出来的是二进制可执行文件.

runtime.GOOS 		// 操作系统
runtime.GC() 		// 强行进行一次GC

runtime.NumCPU() 		//cup 核数
runtime.GOMAXPROCS(4) 		// 应用使用核数最大值

runtime.NumGoroutine()		 // 此时还在工作的协程的个数(包括主协程)
runtime.Gosched() 		// 协程让出时间片
runtime.Goexit() 		// 协程退出

^_^ os

os.Exit(255) 		// 强制性 立刻!全部!退出Go程序(参数范围: 0--255)
  • 环境变量
// 获取指定的环境变量
os.Getenv("GOROOT")
// 获取全部的环境变量
os.Environ()
// 清空所有环境变量(慎)
os.Clearenv()
  • 目录操作
// 获取Go程序当前的工作目录
os.Getwd() 		

// 确定目录分割符号
os.IsPathSeparator('/')  // true  (Linux下: gap == "/")

// 设定工作目录,如果不手动设定,则默认为main.go文件所在的目录即为工作目录
os.Chdir("./aaa") // 这样设定以后,后面代码中的路径 ./ 就代表 原先 ./aaa/

// 创建 单级目录(参1:目录路径,参2:目录权限), 如果创建的目录存在,则报错
os.Mkdir("./abc", os.ModePerm) //  os.ModePerm == 0777
/*
	os.Mkdir("./config1", 0100) // d--x------
	os.Mkdir("./config2", 0200) // d-w-------
	os.Mkdir("./config3", 0400) // dr--------
	os.Mkdir("./config4", 0000) // d---------
*/

// 创建 多级目录,如果创建的目录存在,不报错
os.MkdirAll("./a/b/c", 0700)

// 修改文件权限
os.Chmod("./test", 0777)


// 删除 指定的文件  or  空的文件夹目录
os.Remove("./abc")

// 删除目录 (以及目录中的全部内容)
os.RemoveAll("./abc")

// 修改 目录 or 文件 名称
os.Rename("./aaa", "./bbb")

// 移动 单文件,类比mv命令
// 移动 单目录,则该目录下的所有 子文件 也会 以递归的方式 一同 移动到目标目录下
os.Rename("./aa.tx", "./bbb/aa.txt")

// 获取文件信息
fileInfo, err := os.Stat("./a.txt")
if err != nil {
	fmt.Println(err)
}
fmt.Println("文件名", fileInfo.Name())       // 文件名 a.txt
fmt.Println("文件大小", fileInfo.Size())      // 文件大小 99
fmt.Println("文件权限", fileInfo.Mode())      // 文件权限 -rw-rw-r--
fmt.Println("文件是否是目录", fileInfo.IsDir())  // 文件是否是目录 false
fmt.Println("文件修改时间", fileInfo.ModTime()) // 文件修改时间 2021-10-10 14:26:18.176703279 +0800 CST+0800 CST
  • 文件操作

判断文件是否存在
go中判断 文件or文件夹 是否存在是通过 方法os.Stat() 返> 回的 错误值 判断的:

/1/、os.Stat() 返回的 错误值 为 nil,说明 文件 存在

/2/、os.Stat() 返回的 错误值 不为nil, 则使用 os.IsNotExist()方法 将这个错误 作为参数,判断这错误是不是 文件不存在 导致的错误,
若是返回为 true, 说明 是因为 不存在 而导致的。

/3/、若是返回为 false, 则说明是其他原因 导致 的 错误。

func isExist(filePath string) (bool, error,string) {
    _, err := os.Stat(path)
    if err == nil {
        return true, nil, “文件存在”
    } else {
        if os.IsNotExist(err) {
            return false, nil, “文件不存在”
        } else {
            return false, err, “包错原因不是因为文件不存在导致的”
        }
    }
}

打开文件流 OpenFile(arr1, arr2, arr3)

参1: 文件路径

参2: 文件模式

O_RDONLY : 只读
O_WRONLY:只写
O_RDWR: 读写双操作

O_APPEND:写入的内容追加到原文件内容
O_TRUNC :写入的内容覆盖掉原文件内容

O_CREATE若文件不存在则创建,然后再获取这个文件; 若文件存在直接获取这个文件
O_EXCL: 文件必须存在, 只能 获取 已有的 文件

O_SYNC同步的方式打开这个文件,意味着 不能 多个 协程同时 向这个文件 写入内容,只能一个一个的排队进行写入操作。同步方式打开的目的:防止多个协程写入的内容发生覆盖

参3: 文件权限

在linux系统下的 文件权限控制: chmod 666 a.txt, 在golang中是四位数字0666的前面的0表示文件,后面的3个数字才表示 文件控制权限。
在window下此参数无效可随便写个值 占位。

// 例1:
file,_ := os.OpenFile("./a.txt", os.O_RDWR | os.O_TRUNC | os.O_CREATE, 0666)

// 语法糖:
file,_ := os.Create("./a.txt")
// 例2:
file,_ := os.OpenFile("./a.txt", os.O_RDONLY, 0666)

// 语法糖:
file,_ := os.Open("./a.txt")

os/exec

Go语言调用Shell与可执行文件

常用api:
  • func Command(name string, arg ...string) *Cmd

返回一个*Cmd, 用于执行name指定的程序(携带arg参数)

  • func (c *Cmd) Run() error

执行Cmd中包含的命令,阻塞直到命令执行完成

  • func (c *Cmd) Start() error

执行Cmd中包含的命令,该方法立即返回,并不等待命令执行完成

  • func (c *Cmd) Wait() error

该方法会阻塞直到Cmd中的命令执行完成,但该命令必须是被Start方法开始执行的

  • func (c *Cmd) Output() ([]byte, error)

执行Cmd中包含的命令,并返回标准输出的切片

  • func (c *Cmd) CombinedOutput() ([]byte, error)

执行Cmd中包含的命令,并返回标准输出与标准错误合并后的切片

  • func (c *Cmd) StdinPipe() (io.WriteCloser, error)

返回一个管道,该管道会在Cmd中的命令被启动后连接到其标准输入

  • func (c *Cmd) StdoutPipe() (io.ReadCloser, error)

返回一个管道,该管道会在Cmd中的命令被启动后连接到其标准输出

  • func (c *Cmd) StderrPipe() (io.ReadCloser, error)

返回一个管道,该管道会在Cmd中的命令被启动后连接到其标准错误

栗子
  • 调用 命令
	// 执行 没有 返回数据到命令行 的命令 (操作类的)
	cmd := exec.Command("touch", "./aaa.txt")
	cmd.Run()

	// 执行 有 返回数据到命令行 的命令 (查询类的)
	cmd2 := exec.Command("ls", "-al")
	res, _ := cmd2.Output()
	fmt.Println(string(res)) 
  • 调用 可执行文件 a.sh
	command := `./a.sh` //前提:test.sh是可执行文件
	cmd := exec.Command("/bin/bash", "-c", command)
	output, _ := cmd.Output() //输出到标准流
	fmt.Println(string(output))

a.sh文件:

#!/bin/bash
rm aaa.txt
./abc  #还可以在这里 再调用别的可执行文件
ls

^_^ bufio

介绍:

bufio包实现了有缓冲的I/O.
大概举个例子: 如果不用缓存,从极限的角度讲 一个 8G的内存条 最多就只能操作 一个 8G 的文件了,超过 8G 内存容不下就崩盘了。
有了缓存就不一样的,本着愚公移山的方式,可以 分批次的 操作大文件。

  • 读取流
// 创建 读取流
reader := bufio.NewReader()

// 读取流 常用api
 res, err := reader.ReadByte()
 res, length, err := reader.ReadRune()
 str, err := reader.ReadString('\n')

// 例:一个字一个字读,直到结束
for {
	res, _, err := reader.ReadRune()
	fmt.Println(string(res))
	if err == io.EOF {
        fmt.Println(“文件读取完毕”)
		break
    }
}

// 例: 一句一句读,直到结束
for {
	res,err := reader.ReadString('\n')
	fmt.Println(res)
	if err == io.EOF {
        fmt.Println(“文件读取完毕”)
		break
    }
}
  • 写入流
// 创建 写入流
writer := bufio.NewWriter()

// 读取流 常用api
writer.WriteByte('a')
writer.WriteRune('你')
writer.WriteString("写入的内容。\n")

writer.Flush()		 // 将 缓冲区的 数据 倒干净 到文件中
  • io.Copy(写入流, 读取流)

集成化io: ioutil,一般用于操作小文件

  • 读写文件
// 集成读取
res,_ := ioutil.ReadFile("./a.txt")
var content string = string(res)
/*
说明:
读取的是 文本文件, 可以用 string() 强转 content,
如果是 音频 或 视频 文件,就不可用string强转了。 
说到底,content是 []byte类型 的 原始数据(二进制)
*/

// 集成写入
content := []byte("abcd\n你好")
ioutil.WriteFile("./abc.txt", content, 0666) 
// 说明: 文件模式 O_CREATE | O_TRUC | O_RDONLY
  • 遍历目录
// 只显示当前目录下的文件,不会递归显示
f, err := ioutil.ReadDir("./aaa")
if err != nil {
	fmt.Println(err)
}
for _, v := range f {
	fmt.Println(v.Name(), v.IsDir(), vSize())
	/*
		a.txt 		false  0
		abcc.txt    false  12465558
		bbb 		true   4096
		wtt 		true   4096
	*/

	// 这里配合 单文件位移, 可以实现 多文件 位移。
	err := os.Rename("./aaa/"+v.Name(), "./bbb/"+v.Name())
	if err != nil {
		fmt.Println(err)
	}
}

^_^ http

请求报文

get请求

res, _ := http.Get("http://httpbin.org/get")

defer res.Body.Close()

content, _ := ioutil.ReadAll(res.Body)
fmt.Println(string(content))

// 发送 http://httpbin.org/get?name=tom;age=15 的带参数的get请求
req, err := http.NewRequest(http.MethodGet, "http://httpbin.org/put", nil)
	if err != nil {
		fmt.Println(err)
	}

	// get 的请求参数
	arr := make(url.Values)
	arr.Add("name", "tom")
	arr.Add("age", "15")

	req.URL.RawQuery = arr.Encode()

	// 发起请求
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		fmt.Println(err)
	}
	defer res.Body.Close()
	content, _ := ioutil.ReadAll(res.Body)
	fmt.Println(string(content))

post请求

res, _ := http.Post("http://localhost:8090/post", " ", nil)

defer res.Body.Close()

content, _ := ioutil.ReadAll(res.Body)
fmt.Println(string(content))
发送 json格式 的请求体数据
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

type man struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	obj := man{"tom", 11}

	jsonObj, _ := json.Marshal(obj)
	fmt.Println(string(jsonObj))

	arr1 := "http://localhost:8090/post"
	arr2 := "application/json"
	arr3 := bytes.NewReader(jsonObj)

	res, _ := http.Post(arr1, arr2, arr3)

	defer res.Body.Close()
	content, _ := ioutil.ReadAll(res.Body)

	fmt.Printf("%s", content)
}
发送 表单格式 的请求体数据
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

func main() {
	// 创建一个 盛放 表单数据 的map
	data := make(url.Values)
	// 加入 表单数据
	data.Add("name", "tom")
	data.Add("age", "18")
	formData := data.Encode()

	arr1 := "http://localhost:8090/post"
	arr2 := "application/x-www-form-urlencoded"
	arr3 := strings.NewReader(formData)
	res, _ := http.Post(arr1, arr2, arr3)

	defer res.Body.Close()
	content, _ := ioutil.ReadAll(res.Body)
	fmt.Printf("%s", content)
}

put请求

http包没有提供可以直接使用的 put和delete 请求方法,通过读取get请求的原码,仿照实现

// 创建一个新的请求
req, err := http.NewRequest(http.MethodPut, "http://localhost:8090/put", nil)
if err != nil {
	fmt.Println(err)
}
// 发起请求
res, err := http.DefaultClient.Do(req)
if err != nil {
	fmt.Println(err)
}
defer res.Body.Close()
content, _ := ioutil.ReadAll(res.Body)
fmt.Println(string(content))

设置请求头

req, err := http.NewRequest(http.MethodPut, "http:/localhost:8090/put", nil)

// 请求头 的 用户代理 的设置 在爬虫的时候 很有用的
req.Header.Add("user-agent", "wanghaiou")

res, err := http.DefaultClient.Do(req)

设置cookie

req, _ := http.NewRequest("GET", "http://localhost:8090/get", nil)

//添加cookie,key为 caller,value为 tom,可以添加多个cookie
cookie1 := &http.Cookie{Name: "caller", Value: "tom", HttpOnly: true}
req.AddCookie(cookie1)

req.Header.Add("name", "tom") // 顺便 再 设置一下 请求头

// resp, err := http.DefaultClient.Do(req)
// 若不使用 上面 默认的 请求客户端,也可以 自己生成一个
clientByWtt := &http.Client{}

res, err := clientByWtt.Do(req)

防止 发出的请求 被多次 重定向

package main

import (
	"errors"
	"fmt"
	"net/http"
)

func countRedirect(req *http.Request, via []*http.Request) error {
	if len(via) > 5 {
		return errors.New("重定向次数太多,老子不请求了")
	}
	return nil
}

func main() {

	request, err := http.NewRequest(http.MethodGet, "http://httpbin.org/absolute-redirect/10", nil)
	if err != nil {
		fmt.Println(err)
	}

	clientBySet := &http.Client{CheckRedirect: countRedirect}

	_, err = clientBySet.Do(request)

	if err != nil {
		panic(err)
	}
}

响应报文

res , _ := http.Get(“http://httpbin.org/get”)

响应体 (res.Body)

content, _ := ioutil.ReadAll(res.Body) //返回 字节切片

状态 (res.Status)

状态码 (res.StatusCode)

响应头 (res.Header)

fmt.Println(res.Header["Content-Type"])

获取 cookies

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/cookiejar"
)

func main() {
	jar, _ := cookiejar.New(nil) //创建cookie容器
	client := &http.Client{
		Jar: jar, // 将容器 配置到 客户请求实例 中
	}
	// 客户请求实例 发起请求
	r, _ := client.Get("http://httpbin.org/cookies/set?name=tom&password=123")
	defer r.Body.Close()

	cookies, _ := ioutil.ReadAll(r.Body)
	fmt.Println(string(cookies))
}

练手:下载一张图片,要求看到实时下载的进度

type Reader struct {
	io.Reader
	Total   int64
	Current int64
}

func (r *Reader) Read(p []byte) (n int, err error) {
	n, err = r.Reader.Read(p)
	r.Current += int64(n)
	fmt.Printf("当前进度:%d%% \n", r.Current*100/r.Total)
	return
}

func main() {
	url := "https://user-gold-cdn.xitu.io/2019/6/30/16ba8cb6465a6418?w=826&h=782&f=png&s=279620"
	r, _ := http.Get(url)
	defer r.Body.Close()

	file, _ := os.Create("./bbb/bbb1.png")
	defer file.Close()

	reader := &Reader{
		Reader: r.Body,
		Total:  r.ContentLength,
	}
//reader 的 Read方法 在此内置调用了,所以 结构体的  Read的方法名是 固定的。
	n, err := io.Copy(file, reader) 	
fmt.Println(n, err) //279620(文件大小) <nil>
}

开启http服务

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
)

func main() {
	http.HandleFunc("/", aaa)
	http.HandleFunc("/who", bbb)

	url := "localhost:9753"
	fmt.Println("监听:", url)
	// 服务监听
	err := http.ListenAndServe(url, nil)
	if err != nil {
		panic(err)
	}
}

func aaa(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "hi")
}

// 路由处理函数
func bbb(w http.ResponseWriter, r *http.Request) {

	fmt.Println(r.Method) // POST
	fmt.Println(r.URL)    // who?aaa=bbbb
	fmt.Println(r.Header)

	defer r.Body.Close()
	res, _ := ioutil.ReadAll(r.Body) // 获取 post的json格式的请求体
	fmt.Println(string(res))

	resp := `{
		"name": "tom",
		"age": 11 
	}`
	io.WriteString(w, resp)
}

^_^ reflect

  • 测试变量用例
type man struct {
	caller string
	Age    int `json:"old"`
}

func (that man) ShowName() {
	fmt.Println(that.caller)
}

func (that man) showAge() {
	fmt.Println(that.Age)
}

func (that man) HowOld(inY int, test string) int {
	fmt.Println(test)
	fmt.Println(that.Age)
	return that.Age + inY
}

// 实例变量
tom := man{
	caller: "TOM",
	Age:    10,
}
  • 类型系统
T := reflect.TypeOf(tom)

T.Name() //string >>---> man

T.Kind() //reflect.Kind >>---> struct
T.Kind().String() //string >>---> struct

T.PkgPath() //string >>---> main
// 不论字段首字母是否大写,都会被统计
T.NumField() //int >>---> 2

// 字段的 索引 由 内部字段顺序 决定
T.Field(0) //reflect.StructField >>---> {Name:caller PkgPath:main Type:string Tag: Offset:0 Index:[0] Anonymous:false}

/* 
  嵌套字段 的 深层索引 查找方式:
  T.FieldByIndex([]int{1,0}) 
*/

T.FieldByName("caller") // 同上

T.Field(1).Tag.Get("json") // string >>---> old
// 只有首字母大写的方法,才会被统计
T.NumMethod() // int >>---> 2

// 方法索引,由 方法名的ASCII决定
T.Method(0) // reflect.Method >>---> {Name:HowOld PkgPath: Type:func(main.man, int, string) int Func:<func(main.man, int, string) int Value> Index:0}

T.MethodByName("HowOld") // 同上

T.Method(0).NumIn() //int >>---> 3 (that也算一个参数)
  • 值系统
V := reflect.ValueOf(&tom).Elem() //reflect.Value >>---> {caller:TOM Age:10}

V.Field(0) //reflect.Value >>---> TOM

V.FieldByName("Age") //reflect.Value >>---> 10

//反射赋值 只能改变 首字母大写的字段
V.FieldByName("Age").SetInt(int64(20))

V.FieldByName("Age").Int() //转为正射变量
// 无参调用
arr := []reflect.Value{}
V.Method(1).Call(arr)

// 有参调用
arr := []reflect.Value{
	reflect.ValueOf(10),
	reflect.ValueOf("aaa---test"),
}
V.Method(0).Call(arr)
  • struct —转--->map
func main() {
	obj := struct {
		name string 
		sex  string 
		age  int   
	}{
		"tom",
		"man",
		11,
	}

	m := make(map[string]interface{}, 10)

	v := reflect.ValueOf(&obj).Elem()
	t := reflect.TypeOf(obj)

	for i := 0; i < t.NumField(); i++ {
		switch t.Field(i).Type.String() {
		case "string":
			m[t.Field(i).Name] = v.Field(i).String()
		case "int":
			m[t.Field(i).Name] = v.Field(i).Int()

		default:
			continue
		}
	}
	fmt.Println(m)                      // map[age:11 name:tom sex:man]
	fmt.Println(m["age"].(int64) == 11)  //  true
}
  • map数据 通过tag 对应到 结构体
type aaa struct {
	Tag1 float64 `mp:"tag1"`
	Tag2 float64 `mp:"tag2"`
	Tag3 float64 `mp:"tag3"`
}

func main() {
	inData := map[string]float64{
		"tag1": 1,
		"tag2": 11,
		"tag3": 111,
	}
	obj := aaa{}
	V := reflect.ValueOf(&obj).Elem() //obj址类型
	T := reflect.TypeOf(obj) // obj值类型

	for k, v := range inData {
		for i := 0; i < T.NumField(); i++ {
			if T.Field(i).Tag.Get("mp") == k {
				V.Field(i).SetFloat(v)
			}
		}
	}
	fmt.Println(obj)
}

^_^ sort

切片元素排序

	s := []string{"name", "tom", "abc"}
	fmt.Println(s)  // [name tom abc]
	sort.Strings(s) // 按照字母进行排序
	fmt.Println(s)  // [abc name tom]

	i := []int{5, 1, 3}
	fmt.Println(i) //[5 1 3]
	sort.Ints(i)   // 按照数字进行排序
	fmt.Println(i) // [1 3 5]

	// sort.Float64s
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值