这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记
Go语言基础学习
基础语法
2_1 Hello World
package main import ( "fmt ) func main(){ fmt.Println("hello world") }PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\01-hello\main.go" hello world
补充 自增语句i++给i加1;这和i += 1以及i = i + 1都是等价的。对应的还有i--给i减1。它们是语句,而不像C系的其它语言那样是表达式。所以j = i++非法,而且 ++和--都只能放在变量名后面,因此**--i**也非法
2_2 变量
// var name = value 第一种定义的方式 var a = "initial" // 定义字符串变量 var b, c int = 1, 2//定义整数变量 var d = true//定义布尔类型变量 var e float64//定义浮点数变量 f := float32(e)//定义的另一种方式 g := a + "foo" // +号可以用于字符串的拼接 fmt.Println(a, b, c, d, e, f) // initial 1 2 true 0 0 fmt.Println(g) // initialapple //整体与C++差不多 const s string = "constant" // 定义常量 const h = 500000000 const i = 3e20 / h fmt.Println(s, h, i, math.Sin(h), math.Sin(i))PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\02-var\main.go" initial 1 2 true 0 0 initialfoo constant 500000000 6e+11 -0.28470407323754404 0.7591864109375384变量的声明有四种
s := "" var s string var s = "" var s string = ""第一种形式,是一条短变量声明,最简洁,但只能用在函数内部,而不能用于包变量。第二种形式依赖于字符串的默认初始化零值机制,被初始化为"" 。第三种形式用得很少,除非同时声明多个变量。第四种形式显式地标明变量的类型,当变量类型与初值类型相同时,类型冗余,但如果两者类型不同,变量类型就必须了。实践中一般使用前两种形式中的某个,初始值重要的话就显式地指定变量的类型,否则使用隐式初始化。
2_3 判断语句 if else
if 7%2 == 0 { // 注意Go语言中if 后面不需要加括号 fmt.Println("7 is even") } else { fmt.Println("7 is odd") } if 8%4 == 0 { //注意 花括号要和if else 在同一行 fmt.Println("8 is divisible by 4") } if num := 9; num < 0 { fmt.Println(num, "is negative") } else if num < 10 { fmt.Println(num, "has 1 digit") } else { fmt.Println(num, "has multiple digits") }PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\04-if\main.go" 7 is odd 8 is divisible by 4 9 has 1 digit
2.4 循环语句 for
i := 1 for { //注意 Go语言中只有for这一种循环语句 //注意 for语句后面也没有括号 //for里面什么也不写 代表死循环 fmt.Println("loop") break //跳出循环 } for j := 7; j < 9; j++ { //注意花括号要与for在同一行 fmt.Println(j) } for n := 0; n < 5; n++ { if n%2 == 0 { continue //继续循环 } fmt.Println(n) } for i <= 3 { //可以任意省略 fmt.Println(i) i = i + 1 }PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\03-for\main.go" loop 7 8 1 3 1 2 3for循环三个部分不需括号包围。大括号强制要求,左大括号必须和post语句在同一行。
for initialization; condition; post { // zero or more statements }initialization语句是可选的,在循环开始前执行。initalization如果存在,必须是一条简单语句(simple statement),即,短变量声明、自增语句、赋值语句或函数调用。condition是一个布尔表达式(boolean expression),其值在每次循环迭代开始时计算。如果为true则执行循环体语句。post语句在循环体执行结束后执行,之后再次对condition求值。condition值为false时,循环结束。 for循环的这三个部分每个都可以省略,如果省略initialization和post,分号也可以省略
for循环的另一种形式————在某种数据类型的区间(range)上遍历,如字符串或切片
func main() { s, sep := "", "" for _, arg := range os.Args[1:] { // 使用下划线来丢弃不需要的索引值 s += sep + arg sep = " " } fmt.Println(s) }每次循环迭代,range产生一对值;索引以及在该索引处的元素值。这个例子不需要索引,但range的语法要求,要处理元素,必须处理索引。一种思路是把索引赋值给一个临时变量(如temp)然后忽略它的值,但Go语言不允许使用无用的局部变量(local variables),因为这会导致编译错误。 Go语言中这种情况的解决方法是用空标识符(blank identifier),即_(也就是下划线) 。空标识符可用于在任何语法需要变量名但程序逻辑不需要的时候(如:在循环里)丢弃不需要的循环索引,并保留元素值。
2.5 条件语句 switch
a := 2 switch a { // 注意 Go语言中 case后面不需要加上break语句 ———— 不会顺序执行 case 1: fmt.Println("one") case 2: fmt.Println("two") case 3: fmt.Println("three") case 4, 5: fmt.Println("four or five") default: fmt.Println("other") } t := time.Now() switch { // go语言中switch甚至可以不写 判断变量 case t.Hour() < 12: // 可以判断范围————可以取代if语句 fmt.Println("It's before noon") default: fmt.Println("It's after noon") }PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\05-switch\main.go" two It's after noon
2.6 数组
var a [5]int // 定义有五个int类型的数组a a[4] = 100 fmt.Println("get:", a[2]) fmt.Println("len:", len(a)) b := [5]int{1, 2, 3, 4, 5} fmt.Println(b) var twoD [2][3]int for i := 0; i < 2; i++ { for j := 0; j < 3; j++ { twoD[i][j] = i + j } } fmt.Println("2d: ", twoD)PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\06-array\main.go" get: 0 len: 5 [1 2 3 4 5] 2d: [[0 1 2] [1 2 3]]数组的每个元素可以通过索引下标来访问,索引下标的范围是从0开始到数组长度减1的位置。内置的len函数将返回数组中元素的个数。
在数组字面值中,如果在数组的长度位置出现的是“...”省略号,则表示数组的长度是根据初始化值的个数来计算。
默认情况下,数组的每个元素都被初始化为元素类型对应的零值,对于数字类型来说就是0。 我们也可以使用数组字面值语法用一组值来初始化数组
数组的长度是数组类型的一个组成部分,因此[3]int和[4]int是两种不同的数组类型。数组的长度必须是常量表达式,因为数组的长度需要在编译阶段确定
2.7 切片
s := make([]string, 3) // 使用make 来创建切片 //切片可以像数组一样向里面写值 //切片更加灵活,可以随时更改长度 s[0] = "a" s[1] = "b" s[2] = "c" fmt.Println("get:", s[2]) // c fmt.Println("len:", len(s)) // 3 s = append(s, "d") //向切片中添加元素 s = append(s, "e", "f") fmt.Println(s) // [a b c d e f] c := make([]string, len(s)) copy(c, s)//可以复制切片 fmt.Println(c) // [a b c d e f] fmt.Println(s[2:5]) // [c d e] 左闭右开 fmt.Println(s[:5]) // [a b c d e] 省略去 fmt.Println(s[2:]) // [c d e f] good := []string{"g", "o", "o", "d"} fmt.Println(good) // [g o o d]PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\06-array\main.go" get: 0 len: 5 [1 2 3 4 5] 2d: [[0 1 2] [1 2 3]]要注意的是slice的第一个元素并不一定就是数组的第一个元素。长度对应slice中元素的数目;长度不能超过容量,容量一般是从slice的开始位置到底层数据的结尾位置。内置的len和cap函数分别返回slice的长度和容量。
因为slice值包含指向第一个slice元素的指针,因此向函数传递slice将允许在函数内部修改底层数组的元素。换句话说,复制一个slice只是对底层的数组创建了一个新的slice别名(§2.3.2)。下面的reverse函数在原内存空间将[]int类型的slice反转,而且它可以用于任意长度的slice。
a := [...]int{0, 1, 2, 3, 4, 5} reverse(a[:]) fmt.Println(a) // "[5 4 3 2 1 0]"技巧:
一种将slice元素循环向左旋转n个元素的方法是三次调用reverse反转函数,第一次是反转开头的n个元素,然后是反转剩下的元素,最后是反转整个slice的元素。(如果是向右循环旋转,则将第三个函数调用移到第一个调用位置就可以了。
s := []int{0, 1, 2, 3, 4, 5} // Rotate s left by two positions. reverse(s[:2]) reverse(s[2:]) reverse(s) fmt.Println(s) // "[2 3 4 5 0 1]"和数组不同的是,slice之间不能比较,因此我们不能使用==操作符来判断两个slice是否含有全部相等元素。
一个零值的slice等于nil。一个nil值的slice并没有底层数组。一个nil值的slice的长度和容量都是0,但是也有非nil值的slice的长度和容量也是0的,例如[]int{}或make([]int, 3)[3:]。与任意类型的nil值一样,我们可以用[]int(nil)类型转换表达式来生成一个对应类型slice的nil值。
var s []int // len(s) == 0, s == nil s = nil // len(s) == 0, s == nil s = []int(nil) // len(s) == 0, s == nil s = []int{} // len(s) == 0, s != nil如果你需要测试一个slice是否是空的,使用len(s) == 0来判断,而不应该用s == nil来判断。除了和nil相等比较外,一个nil值的slice的行为和其它任意0长度的slice一样;例如reverse(nil)也是安全的
内置的make函数创建一个指定元素类型、长度和容量的slice。容量部分可以省略,在这种情况下,容量将等于长度。
make([]T, len) make([]T, len, cap) // same as make([]T, cap)[:len]
2.8 (哈希)map
m := make(map[string]int) // 创建map键值对 m["one"] = 1 m["two"] = 2 fmt.Println(m) // map[one:1 two:2] fmt.Println(len(m)) // 2 fmt.Println(m["one"]) // 1 fmt.Println(m["unknow"]) // 0 r, ok := m["unknow"] // 加上ok 用来获取map中是否有这个元素存在 fmt.Println(r, ok) // 0 false delete(m, "one") //删除map中的一个键值对 // map中迭代顺序是随机的!!! m2 := map[string]int{"one": 1, "two": 2} var m3 = map[string]int{"one": 1, "two": 2} fmt.Println(m2, m3)PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\anet\文档\Golang_learn> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\08-map\main.go" map[one:1 two:2] 2 1 0 0 false我们也可以用map字面值的语法创建map,同时还可以指定一些最初的key/value:
ages := map[string]int{ "alice": 31, "charlie": 34, }所有这些操作是安全的,即使这些元素不在map中也没有关系;如果一个查找失败将返回value类型对应的零值
但是map中的元素并不是一个变量,因此我们不能对map的元素进行取址操作
禁止对map元素取址的原因是map可能随着元素数量的增长而重新分配更大的内存空间,从而可能导致之前的地址无效。
Map的迭代顺序是不确定的,并且不同的哈希函数实现可能导致不同的遍历顺序。在实践中,遍历的顺序是随机的,每一次遍历的顺序都不相同。这是故意的
如果要按顺序遍历key/value对,我们必须显式地对key进行排序,可以使用sort包的Strings函数对字符串slice进行排序。下面是常见的处理方式:
import "sort" var names []string for name := range ages { names = append(names, name) } sort.Strings(names) for _, name := range names { fmt.Printf("%s\t%d\n", name, ages[name]) // 对key进行排序,再按照排序完成的key来对应的输出value }因为我们一开始就知道names的最终大小,因此给slice分配一个合适的大小将会更有效。下面的代码创建了一个空的slice,但是slice的容量刚好可以放下map中全部的key:
names := make([]string, 0, len(ages))map类型的零值是nil,也就是没有引用任何哈希表
map上的大部分操作,包括查找、删除、len和range循环都可以安全工作在nil值的map上,它们的行为和一个空的map类似。但是向一个nil值的map存入元素将导致一个panic异常
通过key作为索引下标来访问map将产生一个value。如果key在map中是存在的,那么将得到与key对应的value;如果key不存在,那么将得到value对应类型的零值
但是有时候可能需要知道对应的元素是否真的是在map之中。例如,如果元素类型是一个数字,你可能需要区分一个已经存在的0,和不存在而返回零值的0,可以像下面这样测试:
age, ok := ages["bob"] if !ok { /* "bob" is not a key in this map; age == 0. */ } // 花括号中间的为如果不存在时输出的信息你会经常看到将这两个结合起来使用,像这样:
if age, ok := ages["bob"]; !ok { /* ... */ }和slice一样,map之间也不能进行相等比较;唯一的例外是和nil进行比较。要判断两个map是否包含相同的key和value,我们必须通过一个循环实现
func equal(x, y map[string]int) bool { if len(x) != len(y) { return false } for k, xv := range x { if yv, ok := y[k]; !ok || yv != xv { //注意使用ok来区分元素是否存在,而不是使用== return false } } return true }
2.9 range
nums := []int{2, 3, 4} sum := 0 for i, num := range nums { //使用range遍历数组 第一个值是索引 第二个才是对应的值 // 使用range来进行遍历,可以使得代码更加整洁 sum += num if num == 2 { fmt.Println("index:", i, "num:", num) // index: 0 num: 2 } } fmt.Println(sum) // 9 m := map[string]string{"a": "A", "b": "B"} for k, v := range m { //使用range遍历map 第一个是key 第二个是value fmt.Println(k, v) // b 8; a A } for k := range m { fmt.Println("key", k) // key a; key b }
2.10 函数
func add(a int, b int) int { // 变量类型后置 return a + b } func add2(a, b int) int { return a + b } func exists(m map[string]string, k string) (v string, ok bool) { v, ok = m[k] return v, ok } func main() { res := add(1, 2) fmt.Println(res) // 3 v, ok := exists(map[string]string{"a": "A"}, "a") fmt.Println(v, ok) // A True }PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\10-func\main.go" 3 A true函数声明包括函数名、形式参数列表、返回值列表(可省略)以及函数体。
函数的类型被称为函数的签名。如果两个函数形式参数列表和返回值列表中的变量类型一一对应,那么这两个函数被认为有相同的类型或签名。形参和返回值的变量名不影响函数签名,也不影响它们是否可以以省略参数类型的形式表示。
2.11 指针
func add2(n int) { n += 2 } func add2ptr(n *int) { //指针+ 函数 *n += 2 } func main() { n := 5 add2(n) fmt.Println(n) // 5 add2ptr(&n) //指针 ————go语言中指针用处很小,只用于对传入的参数进行修改 fmt.Println(n) // 7 }PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn> > go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\10-func\main.go"3 A true
2.12 结构体
type user struct { // 定义结构体 name string password string } func main() { a := user{name: "wang", password: "1024"} //结构体 初始化 b := user{"wang", "1024"} c := user{name: "wang"} // 未定义的"password"为初值0 c.password = "1024" var d user d.name = "wang" d.password = "1024" //结构体作为函数参数 fmt.Println(a, b, c, d) // {wang 1024} {wang 1024} {wang 1024} {wang 1024} fmt.Println(checkPassword(a, "haha")) // false //非指针用法 fmt.Println(checkPassword2(&a, "haha")) // false //指针用法 } func checkPassword(u user, password string) bool { return u.password == password } func checkPassword2(u *user, password string) bool { //使用指针操作结构体 可以避免一些大型结构体的过度开销 也可以直接对结构体进行操作 return u.password == password }PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn>> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\12-struct\main.go" {wang 1024} {wang 1024} {wang 1024} {wang 1024} false false结构体的字段可以是任何类型,甚至是结构体本身(参考第 10.5 节),也可以是函数或者接口(参考第 11 章)。
使用 new 函数给一个新的结构体变量分配内存,它返回指向已分配内存的指针:
var t *T = new(T),如果需要可以把这条语句放在不同的行(比如定义是包范围的,但是分配却没有必要在开始就做)写这条语句的惯用方法是:
t := new(T),变量t是一个指向T的指针,此时结构体字段的值是它们所属类型的零值。
2.13 结构体方法
type user struct { name string password string } func (u user) checkPassword(password string) bool { // user位置变成了函数名的前面 return u.password == password } func (u *user) resetPassword(password string) { u.password = password } func main() { a := user{name: "wang", password: "1024"} a.resetPassword("2048") // 注意 a.+函数名 fmt.Println(a.checkPassword("2048")) // true }PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\13-struct-method\main.go" trueGo 方法是作用在接收者(receiver)上的一个函数,接收者是某种类型的变量。因此方法是一种特殊类型的函数。
定义方法的一般格式如下:
func (recv receiver_type) methodName(parameter_list) (return_value_list) { ... }在方法名之前,
func关键字之后的括号中指定 receiver。如果
recv是 receiver 的实例,Method1 是它的方法名,那么方法调用遵循传统的object.name选择器符号:recv.Method1() 。如果
recv一个指针,Go 会自动解引用。如果方法不需要使用
recv的值,可以用 _ 替换它,比如:func (_ receiver_type) methodName(parameter_list) (return_value_list) { ... }
recv就像是面向对象语言中的this或self,但是 Go 中并没有这两个关键字。随个人喜好,你可以使用this或self作为 receiver 的名字
2.14 错误处理
type user struct { name string password string } func findUser(users []user, name string) (v *user, err error) { //加上error 可以返回错误 for _, u := range users { if u.name == name { return &u, nil } } return nil, errors.New("not found") } func main() { u, err := findUser([]user{{"wang", "1024"}}, "wang") if err != nil { //可以判断错误 fmt.Println(err) return } fmt.Println(u.name) // wang if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil { fmt.Println(err) // not found return } else { fmt.Println(u.name) } }PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\13-struct-method\main.go" true
2.15 字符串操作
func main() { a := "hello" fmt.Println(strings.Contains(a, "ll")) // true //判断一个字符串里是否包含另一个字符串 fmt.Println(strings.Count(a, "l")) // 2 //字符串中某一个字符的数量 fmt.Println(strings.HasPrefix(a, "he")) // true fmt.Println(strings.HasSuffix(a, "llo")) // true fmt.Println(strings.Index(a, "ll")) // 2 //返回某个字符串再大字符串中的位置 fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo //连接多个字符串 fmt.Println(strings.Repeat(a, 2)) // hellohello //重复多个字符串 fmt.Println(strings.Replace(a, "e", "E", -1)) // hEllo、 //替换字符串 fmt.Println(strings.Split("a-b-c", "-")) // [a b c] //字符串划分 fmt.Println(strings.ToLower(a)) // hello //字符串全部小写 fmt.Println(strings.ToUpper(a)) // HELLO //字符串全部大写 fmt.Println(len(a)) // 5 b := "你好" //一个中文字符占3的长度 fmt.Println(len(b)) // 6 }PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\15-string\main.go" true 2 true true 2 he-llo hellohello hEllo [a b c] hello HELLO 5 6
2.16 字符串格式化
func main() { s := "hello" n := 123 p := point{1, 2} fmt.Println(s, n) // hello 123 fmt.Println(p) // {1 2} fmt.Printf("s=%v\n", s) // s=hello //可以用%V 来打印任意类型的东西 fmt.Printf("n=%v\n", n) // n=123 fmt.Printf("p=%v\n", p) // p={1 2} fmt.Printf("p=%+v\n", p) // p={x:1 y:2} //%+v 会输出较为详细的结果 fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2} //%#v 会输出非常详细 的结果 f := 3.141592653 fmt.Println(f) // 3.141592653 fmt.Printf("%.2f\n", f) // 3.14 //保留2位小数点 }PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\16-fmt\main.go" hello 123 {1 2} s=hello n=123 p={1 2} p={x:1 y:2} p=main.point{x:1, y:2} 3.141592653 3.14
2.17 JSON处理
package main import ( "encoding/json" "fmt" ) type userInfo struct { //只需保证结构体的每一个字段的第一个字母是大写即可 Name string Age int `json:"age"` //这样在json后可以输出小写形式的 Hobby []string } func main() { a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}} buf, err := json.Marshal(a) //数列化 if err != nil { panic(err) } fmt.Println(buf) // [123 34 78 97...] //十六进制的编码 fmt.Println(string(buf)) // {"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]} // 注意age为小写 buf, err = json.MarshalIndent(a, "", "\t") if err != nil { panic(err) } fmt.Println(string(buf)) var b userInfo err = json.Unmarshal(buf, &b) //反数列化 if err != nil { panic(err) } fmt.Printf("%#v\n", b) // main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}} }PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\17-json\main.go" [123 34 78 97 109 101 34 58 34 119 97 110 103 34 44 34 97 103 101 34 58 49 56 44 34 72 111 98 98 121 34 58 91 34 71 111 108 97 110 103 34 44 34 84 121 112 101 83 99 114 105 112 116 34 93 125] {"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]} { "Name": "wang", "age": 18, "Hobby": [ "Golang", "TypeScript" ] } main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}
2.18 时间处理
func main() { now := time.Now() // 获取现在的时间 fmt.Println(now) // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933 t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC) //构造一个带时区的 t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC) fmt.Println(t) // 2022-03-27 01:25:36 +0000 UTC fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25 //分别获取时间的年 月 日 小时 分钟 fmt.Println(t.Format("2006-01-02 15:04:05")) //格式化时间 // 2022-03-27 01:25:36 diff := t2.Sub(t) fmt.Println(diff) // 1h5m0s fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900 t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")//解析成时间 if err != nil { panic(err) } fmt.Println(t3 == t) // true fmt.Println(now.Unix()) // 1648738080 //获取时间戳 }PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\18-time\main.go" 2022-05-07 20:37:05.1232101 +0800 CST m=+0.007884801 2022-03-27 01:25:36 +0000 UTC 2022 March 27 1 25 2022-03-27 01:25:36 1h5m0s 65 3900 true 1651927025
2.19 数字解析
package main import ( "fmt" "strconv" //转换所使用的包 ) func main() { //字符串与数字之间的转换 f, _ := strconv.ParseFloat("1.234", 64) //解析字符串 fmt.Println(f) // 1.234 n, _ := strconv.ParseInt("111", 10, 64) //解析字符串 //三个参数 ———— 第一个为传入的字符串 第二个XX进制 第三个为XX精度 fmt.Println(n) // 111 n, _ = strconv.ParseInt("0x1000", 0, 64) fmt.Println(n) // 4096 n2, _ := strconv.Atoi("123") //快速转换十进制字符串到数字 //.Itoa() 可以快速转换数字到十进制的字符串 fmt.Println(n2) // 123 n2, err := strconv.Atoi("AAA") // 输入的数字不合法会返回错误 fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax }PS C:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn> go run "c:\Users\Dragonsss\OneDrive - 21Vianet\文档\Golang_learn\go-by-example\example\19-strconv\main.go" 1.234 111 4096 123
2.20 进程信息
package main import ( "fmt" "os" "os/exec" ) func main() { // go run example/20-env/main.go a b c d //可以直接执行一个go的源文件 fmt.Println(os.Args) //临时目录+ abcd [/var/folders/8p/n34xxfnx38dg8bv_x8l62t_m0000gn/T/go-build3406981276/b001/exe/main a b c d] fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin... //获取或者写入环境变量 fmt.Println(os.Setenv("AA", "BB")) buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput() //exec.Comamand快速启动子进程来获取输入与输出 if err != nil { panic(err) } fmt.Println(string(buf)) // 127.0.0.1 localhost }\