记录一下之前的Go学习笔记。

1. switch

 1package main
 2
 3import (
 4	"fmt"
 5	"os"
 6)
 7
 8//从命令输入参数,在switch中进行处理
 9
10func main() {
11	//C: argc , **argv
12	//Go: os.Args ==> 直接可以获取命令输入,是一个字符串切片 []string
13	cmds := os.Args
14
15	//os.Args[0] ==> 程序名字
16	//os.Args[1] ==> 第一个参数 ,以此类推
17	for key, cmd := range cmds {
18		fmt.Println("key:", key, ", cmd:", cmd, ", cmds len:", len(cmds))
19	}
20
21	if len(cmds) < 2 {
22		fmt.Println("请正确输入参数!")
23		return
24	}
25
26	switch cmds[1] {
27	case "hello":
28		fmt.Println("hello")
29		//go 的switch, 默认加上break了,不需要手动处理
30		//如果想向下穿透的话,那么需要加上关键字: fallthrough
31		fallthrough
32	case "world":
33		fmt.Println("world")
34	default:
35		fmt.Println("default called!")
36	}
37}

运行结果:

1key: 0 , cmd: C:\Users\Admin\AppData\Local\JetBrains\GoLand2025.1\tmp\GoLand\___go_build_main_go.exe , cmds len: 1
2请正确输入参数!
3
4Process finished with the exit code 0

2. 标签

 1package main
 2
 3import "fmt"
 4
 5func main() {
 6	//标签 LABEL1
 7	//goto LABEL  ===> 下次进入循环时,i不会保存之前的状态,重新从0开始计算,重新来过
 8	//continue LABEL1 ===> continue会跳到指定的位置,但是会记录之前的状态,i变成1
 9	//break LABEL1  ==> 直接跳出指定位置的循环
10
11	//标签的名字是自定义的,后面加上冒号
12LABEL121:
13	for i := 0; i < 5; i++ {
14		for j := 0; j < 5; j++ {
15			if j == 3 {
16				//goto LABEL1
17				//continue LABEL1
18				break LABEL121
19				//break
20			}
21
22			fmt.Println("i:", i, ",j:", j)
23		}
24	}
25
26	fmt.Println("over!")
27}

运行结果:

1i: 0 ,j: 0
2i: 0 ,j: 1
3i: 0 ,j: 2
4over!

3. 枚举const+iota

 1package main
 2
 3import "fmt"
 4
 5//在go语言中没有枚举类型,但是我们可以使用const + iota(常量累加器)来进行模拟
 6//模拟一个一周的枚举
 7const (
 8	MONDAY    = iota       //0
 9	TUESDAY   = iota       //1
10	WEDNESDAY = iota       //2
11	THURSDAY               //3  ==> 没有赋值,默认与上一行相同iota ==> 3
12	FRIDAY                 //4
13	SATURDAY               //5
14	SUNDAY                 //6
15	M, N      = iota, iota //const属于预编译期赋值,所以不需要:=进行自动推导
16)
17
18const (
19	JANU = iota + 1 //1
20	FER             //2
21	MAR             //3
22	APRI            //4
23)
24
25//1. iota是常量组计数器
26//2.iota从0开始,每换行递增1
27//3. 常量组有个特点如果不赋值,默认与上一行表达式相同
28//4.如果同一行出现两个iota,那么两个iota的值是相同的
29//5.每个常量组的iota是独立的,如果遇到const iota会重新清零
30
31func main() {
32
33	fmt.Println("打印周:")
34	fmt.Println(MONDAY)
35	fmt.Println(TUESDAY)
36	fmt.Println(WEDNESDAY)
37	fmt.Println(THURSDAY)
38	fmt.Println(FRIDAY)
39	fmt.Println("M:", M, ",N:", N)
40
41	fmt.Println("打印月份:")
42	fmt.Println(JANU) //1
43	fmt.Println(FER)  //2
44	fmt.Println(MAR)  //3
45
46	//var number int
47	//var name string
48	//var flag bool
49	//
50	//
51	////可以使用变量组来将统一定义变量
52	//var (
53	//	number int
54	//	name string
55	//	flag bool
56	//)
57
58}

运行结果:

 1打印周:
 20
 31
 42
 53
 64
 7M: 7 ,N: 7
 8打印月份:
 91
102
113
12
13Process finished with the exit code 0

在goland中配置git shell,并且显示中文:

https://www.bbsmax.com/A/n2d9YvN6dD/

1我的安装路径D:\Program Files (x86)\Tools\Git\Git\etc)下bash.bashrc文件
2
3export LANG="zh_CN.UTF-8"
4export LC_ALL="zh_CN.UTF-8"

4. 结构体

在go语言中,使用结构体来模拟类

 1package main
 2
 3import "fmt"
 4
 5//c语言里面,我们可以使用typedef  int MyInt
 6type MyInt int //type相当于typdef
 7
 8//C:
 9//struct Person {
10//
11//}
12
13//go语言结构体使用type + struct来处理
14type Student struct {
15	name   string
16	age    int
17	gender string
18	score  float64
19}
20
21func main() {
22    t1 := struct {
23        a int
24    }{
25        a : 100,
26    }
27    
28    fmt.Println(t1)
29    
30	var i, j MyInt
31	i, j = 10, 20
32
33	fmt.Println("i+j:", i+j)
34
35	//创建变量,并赋值
36	lily := Student{
37		name:   "Lily",
38		age:    20,
39		gender: "女生",
40		//score:  80, //最后一个元素后面必须加上逗号,如果不加逗号则必须与}同一行
41		//}
42		score: 80} //最后一个元素后面必须加上逗号,如果不加逗号则必须与}同一行
43
44	//使用结构体各个字段
45	fmt.Println("lily:", lily.name, lily.age, lily.gender, lily.score)
46
47	//结构体没有-> 操作
48	s1 := &lily
49	fmt.Println("lily 使用指针s1.name打印:", s1.name, s1.age, s1.gender, s1.score)
50	fmt.Println("lily 使用指针(*s1).name打印:", (*s1).name, s1.age, s1.gender, s1.score)
51
52	//在定义期间对结构体赋值时,如果每个字段都赋值了,那么字段的名字可以省略不写
53	//如果只对局部变量赋值,那么必须明确指定变量名字
54	Duke := Student{
55		name: "Duke",
56		age:  28,
57		//"男生",
58		// 99,
59	}
60	Duke.gender = "男生"
61	Duke.score = 100
62
63	fmt.Println("Duke:", Duke)
64}

运行结果:

1{100}
2i+j: 30
3lily: Lily 20 女生 80
4lily 使用指针s1.name打印: Lily 20 女生 80
5lily 使用指针(*s1).name打印: Lily 20 女生 80
6Duke: {Duke 28 男生 100}
7
8Process finished with the exit code 0

5.init函数

C语言没有init函数,C语言一般需要自己去写init,然后在构造函数中调用

Go语言自带init函数,每一个包都可以包含一个或多个init函数

 1package sub
 2
 3import "fmt"
 4
 5//0.这个init会在包被引用的时候(import)进行自动调用
 6//1.init函数没有参数,没有返回值,原型固定如下
 7//2.一个包中包含多个init时,调用顺序是不确定的(同一个包的多个文件中都可以有init)
 8//3. init函数时不允许用户显示调用的
 9//4. 有的时候引用一个包,可能只想使用这个包里面的init函数(mysql的init对驱动进行初始化)
10//但是不想使用这个包里面的其他函数,为了防止编译器报错,可以使用_形式来处理
11//import _ "xxx/xx/sub"
12func init() {
13	fmt.Println("this is first init() in package sub ==> sub.go")
14}
15
16func init() {
17	fmt.Println("this is second init() in package sub ==> sub.go ")
18}
19
20//在go语言中,同一层级目录,不允许出现多个包名
21func Sub(a, b int) int {
22	//init() ==> 不允许显示调用
23	test4() //由于test4与sub.go在同一个包下面,所以可以使用,并且不需要sub.形式
24	return a - b
25}

utils.go

 1package sub
 2
 3//package utils //不允许出现多个包名
 4
 5import "fmt"
 6
 7func init() {
 8	fmt.Println("this is init in sub utils.go")
 9}
10
11func test4() {
12	fmt.Println("this is test4() in sub/utils!")
13}

main.go

 1package main
 2
 3import (
 4	_ "day02/05-init函数/sub" //此时,只会调用sub里面的init函数,编译还不会出错
 5	//"fmt"
 6)
 7
 8func main() {
 9	//res := sub.Sub(10, 5)
10	//fmt.Println("sub.Sub(20,10) =", res)
11}

效果:

1586054701758

使用init场景,在配置文件管理器中写init,用于加载配置文件并解析:

1configManager {
2	//解析加载配置文件
3	//IP, PORT
4}

1586055043410

6.defer(延迟)

延迟,关键字,可以用于修饰语句,函数,确保这条语句可以在当前栈退出的时候执行

1lock.Lock()
2a = "hello"
3lock.Unlock()   <=== 经常容易忘掉解锁

go语言可以使用defer来解决这个问题

 1{
 2    lock.Lock()
 3    defer lock.Unlock()   <=== 在当前栈退出的时候(例如:函数结束时)
 4    a = "hello"
 5}
 6
 7{
 8    f1,_ := file.Open()
 9    defer f1.Close()
10}

实例:

 1package main
 2
 3import (
 4	"fmt"
 5	"os"
 6)
 7
 8func main() {
 9	//1.延迟,关键字,可以用于修饰语句,函数,确保这条语句可以在当前栈退出的时候执行
10	//2. 一般用于做资源清理工作
11	//3. 解锁、关闭文件
12	//4. 在同一个函数中多次调用defer,执行时类似于栈的机制:先后入后出
13
14	filename := "mail.go"
15	readFile(filename)
16}
17
18func readFile(filename string) {
19	//func Open(name string) (*File, error) {
20	//1. go语言一般会将错误码作为最后一个参数返回
21	//2. err一般nil代表没有错误,执行成功,非nil表示执行失败
22	f1, err := os.Open(filename)
23
24	//匿名函数,没有名字,属于一次性的逻辑 ==> lamada表达式
25	defer func(a int) {
26		fmt.Println("准备关闭文件, code:", a)
27		_ = f1.Close()
28	}(100) //创建一个匿名函数,同时调用
29
30	if err != nil {
31		fmt.Println("os.Open(\"mail.go\") ==> 打开文件失败, err:", err)
32		return
33	}
34
35	defer fmt.Println("0000000")
36	defer fmt.Println("1111111")
37	defer fmt.Println("2222222")
38
39    buf := make([]byte, 1024)  //byte ==> char ==> uint8
40	//func (f *File) Read(b []byte) (n int, err error) {
41	n, _ := f1.Read(buf)
42	fmt.Println("读取文件的实际长度:", n)
43	fmt.Println("读取的文件内容:", string(buf))  ==> 类型转换
44
45}

运行结果:

 1读取文件的实际长度: 1024
 2读取的文件内容: package main
 3
 4import (
 5	"fmt"
 6	"os"
 7)
 8
 9func main() {
10	//1.延迟,关键字,可以用于修饰语句,函数,确保这条语句可以在当前栈退出的时候执行
11	//2. 一般用于做资源清理工作
12	//3. 解锁、关闭文件
13	//4. 在同一个函数中多次调用defer,执行时类似于栈的机制:先后入后出
14
15	filename := "main.go"
16	readFile(filename)
17}
18
19func readFile(filename string) {
20	//func Open(name string) (*File, error) {
21	//1. go语言一般会将错误码作为最后一个参数返回
22	//2. err一般nil代表没有错误,执行成功,非nil表示执行失败
23	f1, err := os.Open(filename)
24
25	//匿名函数,没有名字,属于一次性的逻辑 ==> lamada表达式
26	defer func(a int) {
27		fmt.Println("准备关闭文件, code:", a)
28		_ = f1.Close()
29	}(100) //创建一个匿名函数,同时调用
30
31	if err != nil {
32		fmt.Println("os.Open(\"mail.go\") ==> 打开文件失败, err:", err)
33		return
34	}
35
36	defer fmt.Println("0000000")
37	defer fmt.Println("1111111")
38	defer fmt.Prin
392222222
401111111
410000000
42准备关闭文件, code: 100
43
44Process finished with the exit code 0