diff --git a/README.en.md b/README.en.md deleted file mode 100644 index dd9284028846b98aa0465bb90726a4ff937d5e5b..0000000000000000000000000000000000000000 --- a/README.en.md +++ /dev/null @@ -1,39 +0,0 @@ -# GO语言学习 - -#### Description -从零开始学习go语言,从入门到实战。 -记录学习笔记和示例 -基础语法、Gin框架、gRPC、gORM..... - - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md index 91b1e42e4438ab3b914704e36ade09aec786944d..b6961f7b742f4ab244f0b4a4c6e20189e818bddb 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,44 @@ -# GO语言学习 - -#### 介绍 -从零开始学习go语言,从入门到实战。 -记录学习笔记和示例 -基础语法、Gin框架、gRPC、gORM..... - - -#### 软件架构 -软件架构说明 - - -#### 安装教程 - -1. xxxx -2. xxxx -3. xxxx - -#### 使用说明 - -1. xxxx -2. xxxx -3. xxxx - -#### 参与贡献 - -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request - - -#### 特技 - -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) +# GO语言学习笔记 + +## 介绍 + +从零开始学习go语言,从入门到实战。 +记录学习笔记和示例 +基础语法、Gin框架、gRPC、gORM..... + +## Go语言历史 + +### 1.诞生时间 + +Go 语言起源 2007 年,并于 2009 年正式对外发布。它从 2009 年 9 月 21 日开始作为谷歌公司 20% 兼职项目, +即相关员工利用 20% 的空余时间来参与 Go 语言的研发工作。 + +### 2. 里程碑 + +- 2007年,谷歌工程师Ken Thompson、Rob Pike、Robert Griesemer开始设计一门全新的语言,这是Go语言的最初原型。 +- 2009.11.10 ,Google将Go语言以开放源代码的形式向全球发布。 +- 2015年8月19日 ,Go1.5版本发布,本次更新中移除了“最后残余的C代码”,请内存管理方面权威专家Rick Hudson对GC进行重新设计(重要的修正) +- 2017年2月16日 , Go1.8版本发布 +- 2017年8月24日 , Go1.9版本发布 +- 2018年2月16日 , Go1.10版本发布 +- 2018年8月24日 , Go1.11版本发布 +- 2019年2月25日 , Go1.12版本发布 +- 2019年9月03日 , Go1.13版本发布 +- 2020年2月25日 , Go1.14版本发布 +- 2020年8月11日 , Go1.15版本发布 +- 2021年2月16日 , Go1.16版本发布 +- 2021年8月16日 , Go1.17版本发布 + +### 3. 为什么使用Go + +1. 简单好记的关键词和语法。轻松上手,简单易学。 +2. 更高的效率。比Java,C++等拥有更高的编译速度,同时运行效率媲美C,同时开发效率非常高。 +3. 生态强大,网络上库很丰富,很多功能使用Go开发非常简单。 +4. 语法检查严格,高安全性。 +5. 严格的依赖管理,go mod命令。 +6. Go拥有强大的编译检查、严格的编码规范和完整的软件生命周期工具,具有很强的稳定性,稳定压倒一切。 +7. 跨平台交叉编译,windows就可以编译出mac,linux上可执行的程序。 +8. 异步编程复杂度低,易维护,GO 语言中 Channel 设计,异步程序写起来非常自然。 +9. 语言层面支持并发,`go关键字(协程)`使得go的并发效率极高。 +10. 严格的语法规范,所有程序员写出来的代码都是一样的,对大团队来说,非常友好。 +11. Go 的并发、性能、安全性、易于部署等特性,使它很容易成为“云原生语言”。容器和云的使用上非常广 diff --git a/go_base/.keep b/go_base/pkg/mod/cache/lock similarity index 100% rename from go_base/.keep rename to go_base/pkg/mod/cache/lock diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo1/demo1.go" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo1/demo1.go" new file mode 100644 index 0000000000000000000000000000000000000000..999317088dfd8638d7456c1d4a9d52b831984b9b --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo1/demo1.go" @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Print("hello world") +} diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo10/demo10.go" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo10/demo10.go" new file mode 100644 index 0000000000000000000000000000000000000000..f567d30ff3db0c86f31e2dc7ae317343748ad759 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo10/demo10.go" @@ -0,0 +1,40 @@ +package main + +import ( + "errors" + "fmt" +) + +func main() { + //invalid operation: nil == nil (operator == not defined on nil) + //fmt.Println(nil == nil) + + //不提倡这样做 + var nil = errors.New("my god") + fmt.Println("nil:", nil) + + //没有默认类型 + //fmt.Printf("%T", nil) + + //不同类型 nil 的指针是一样的 + var arr []int + var num *int + fmt.Printf("%p\n", arr) + fmt.Printf("%p", num) + fmt.Println() + //是 map、slice、pointer、channel、func、interface 的零值 + var m map[int]string + var ptr *int + var c chan int + var sl []int + var f func() + var i interface{} + + fmt.Printf("%#v\n", m) + fmt.Printf("%#v\n", ptr) + fmt.Printf("%#v\n", c) + fmt.Printf("%#v\n", sl) + fmt.Printf("%#v\n", f) + fmt.Printf("%#v\n", i) + +} diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo11/demo11.go" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo11/demo11.go" new file mode 100644 index 0000000000000000000000000000000000000000..7356d11ac4a179f4e9fbfd96170624afe351b3e2 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo11/demo11.go" @@ -0,0 +1,104 @@ +package main + +import ( + "errors" + "fmt" + "os" +) + +func length(s string) int { + println("call length.") + return len(s) +} + +func main() { + s := "abcd" + // 这样写会多次调佣length函数 + for i, n := 0, length(s); i < n; i++ { + println(i, s[i]) + } + +} + +//if else用法 +func ifElse() { + var a = 100 + var b = 200 + + if a == 100 { + if b == 200 { + fmt.Println("a 的值为 100 , b 的值为 200\n") + } + } +} + +//for用法 +func forTest() { + sum := 0 + for i := 0; i < 10; i++ { + sum += i + } + + for { + sum++ + if sum > 100 { + break + } + } + + n := 10 + for n > 0 { + n-- + fmt.Println(n) + } + + m := 2 + for ; m > 0; m-- { + fmt.Println(m) + } +} + +// 99乘法表 +func JjChenFa() { + // 遍历, 决定处理第几行 + for y := 1; y <= 9; y++ { + // 遍历, 决定这一行有多少列 + for x := 1; x <= y; x++ { + fmt.Printf("%d*%d=%d ", x, y, x*y) + } + // 手动生成回车 + fmt.Println() + } +} + +// goto用法 +func goToTest() { + err := firstCheckError() + if err != nil { + fmt.Println(err) + goto onExit + } + err = secondCheckError() + if err != nil { + fmt.Println(err) + goto onExit + } + fmt.Println("done") + return +onExit: + exitProcess() +} + +func firstCheckError() interface{} { + return errors.New("错误1") +} + +func secondCheckError() interface{} { + return errors.New("错误2") +} + +func exitProcess() { + fmt.Println("exit") + //退出 + os.Exit(1) +} diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo12/demo12.go" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo12/demo12.go" new file mode 100644 index 0000000000000000000000000000000000000000..271f9b17bf5bba158c8c1f181d331334744908a3 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo12/demo12.go" @@ -0,0 +1,132 @@ +package main + +import ( + "fmt" + "math" +) + +func main() { + fmt.Println(max(10, 5)) + + fmt.Println(test(5, 6, "和为:")) + + s1 := demo(fn) + fmt.Println(s1) + + s2 := format(formatFun, "%d, %d", 10, 20) + fmt.Println(s2) + + a, b := sum(30, 15) + fmt.Println(a, b) + + c, d, e := demo2() + fmt.Println(c, d, e) + + var f, g = 2, 3 + demo3(&f, &g) + fmt.Println(f, g) + + k := []int{1, 2, 3, 4, 5, 6} + res := demo4("sum: %d", k...) + fmt.Println(res) + + //匿名函数 + sqrt := func(a float64) float64 { + return math.Sqrt(a) + } + fmt.Println(sqrt(10)) + + //在定义时调用匿名函数 + func(data int) { + fmt.Println(data) + }(10) + + visit([]int{4, 5, 6}, func(v int) { + fmt.Println(v) + }) + + m, n := demo5(8, 6) + fmt.Println(m()) + fmt.Println(n(3)) + +} + +//基本写法 +func max(n1, n2 int) int { + if n1 > n2 { + return n1 + } + return n2 +} + +//返回多个值 +func test(x, y int, s string) (int, string) { + sum := x + y + return sum, fmt.Sprintf(s, sum) +} + +//函数作为参数 +func demo(fn func(int2 int) int) int { + return fn(30) +} + +func fn(int2 int) int { + return int2 +} + +// 定义函数类型 +type FormatFunc func(s string, x, y int) string + +func format(fn FormatFunc, s string, x, y int) string { + return fn(s, x, y) +} + +func formatFun(s string, x, y int) string { + return fmt.Sprintf(s, x, y) +} + +//多个返回值 +func sum(a, b int) (int, int) { + return a, b +} + +//返回值命名 +func demo2() (names []string, m map[string]int, num int) { + m = make(map[string]int) + m["a"] = 5 + + return +} + +//引用传递 +func demo3(x, y *int) { + *x, *y = *y, *x +} + +//不定参数 +func demo4(str string, n ...int) string { + var x int + for _, i := range n { + x += i + } + return fmt.Sprintf(str, x) +} + +//匿名函数用作回调函数 +func visit(list []int, f func(int)) { + for _, i := range list { + f(i) + } +} + +//返回多个匿名函数 +func demo5(x, y int) (func() int, func(int) int) { + sum2 := func() int { + return x + y + } + + avg := func(z int) int { + return (x + y) * z + } + return sum2, avg +} diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo2/demo2.go" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo2/demo2.go" new file mode 100644 index 0000000000000000000000000000000000000000..e0b4152711f98413916f3b2d8059ccd414e6cdd1 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo2/demo2.go" @@ -0,0 +1,35 @@ +package main + +import "fmt" + +var name1 string = "老王" +var name2 = "老张" + +var num1, num2, num3 int32 = 10, 20, 30 + +//不能: +//name3 := "老唐" + +const aa string = "jay" +const bb = 100 + +const age1, age2, age3 int32 = 10, 11, 12 +const name4, weight2 = "Jerry", 130 + +func main() { + fmt.Println(name1, name2) + fmt.Println(num1, num2, num3) + //声明了一定要用 + name3 := "老唐" + fmt.Println(name3) + + fmt.Println(aa, bb) + fmt.Println(name4, weight2) + fmt.Println(age1, age2, age3) + + fmt.Print("输出到控制台不换行") + fmt.Println("---") + fmt.Println("输出到控制台并换行") + fmt.Printf("name=%s,age=%d\n", "Tom", 30) + fmt.Printf("name=%s,age=%d,height=%v\n", "Tom", 30, fmt.Sprintf("%.2f", 180.567)) +} diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo3/demo3.go" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo3/demo3.go" new file mode 100644 index 0000000000000000000000000000000000000000..9fdb42b56700925bffc375fa8dc5c8df4f6403a8 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo3/demo3.go" @@ -0,0 +1,31 @@ +package main + +import "fmt" + +func main() { + //一维数组 + var arr1 int + fmt.Println(arr1) + + var arr2 = [3]int{1, 2, 3} + fmt.Println(arr2) + + arr3 := [3]int{1, 2, 3} + fmt.Println(arr3) + + arr4 := [...]int{1, 2, 3} + fmt.Println(arr4) + + arr5 := [...]int{0: 1, 2: 3} + fmt.Println(arr5) + + //二维数组 + var arr6 = [3][5]int{{1, 2, 3}, {3, 4, 5}, {6, 7, 8}} + fmt.Println(arr6) + + arr7 := [3][5]int{{1, 2, 3}, {3, 4, 5}, {6, 7, 8}} + fmt.Println(arr7) + + arr8 := [...][5]int{{1, 2, 3}, {3, 4, 5}, {6, 7, 8}, {1: 4, 3: 5, 4: 7}} + fmt.Println(arr8) +} diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo4/demo4.go" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo4/demo4.go" new file mode 100644 index 0000000000000000000000000000000000000000..5ab7d3f1220e45ea11eeaf8b553deeb689348fab --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo4/demo4.go" @@ -0,0 +1,54 @@ +package main + +import "fmt" + +func main() { + //声明切片 + var sli_1 []int //nil 切片 + fmt.Printf("len=%d cap=%d slice=%v\n", len(sli_1), cap(sli_1), sli_1) + + var sli_2 = []int{} + fmt.Printf("len=%d cap=%d slice=%v\n", len(sli_2), cap(sli_2), sli_2) + + var sli_3 = []int{1, 2, 3, 4, 5} + fmt.Printf("len=%d cap=%d slice=%v\n", len(sli_3), cap(sli_3), sli_3) + + sli_4 := []int{1, 2, 3, 4, 5} + fmt.Printf("len=%d cap=%d slice=%v\n", len(sli_4), cap(sli_4), sli_4) + + var sli_5 []int = make([]int, 5, 8) + fmt.Printf("len=%d cap=%d slice=%v\n", len(sli_5), cap(sli_5), sli_5) + + sli_6 := make([]int, 5, 8) + fmt.Printf("len=%d cap=%d slice=%v\n", len(sli_6), cap(sli_6), sli_6) + + //截取切片 + sli := []int{1, 2, 3, 4, 5, 6} + fmt.Println("sli[1] ==", sli[1]) + fmt.Println("sli[:] ==", sli[:]) + fmt.Println("sli[1:] ==", sli[1:]) + fmt.Println("sli[:4] ==", sli[:4]) + + fmt.Println("sli[2:4] ==", sli[2:4]) //左闭右开 + fmt.Println("sli[0:3:4] ==", sli[0:3:4]) + + //追加 + sli = append(sli, 7) + fmt.Printf("len=%d cap=%d slice=%v\n", len(sli), cap(sli), sli) + sli = append(sli, 8) + fmt.Printf("len=%d cap=%d slice=%v\n", len(sli), cap(sli), sli) + sli = append(sli, 9) + fmt.Printf("len=%d cap=%d slice=%v\n", len(sli), cap(sli), sli) + sli = append(sli, 10) + fmt.Printf("len=%d cap=%d slice=%v\n", len(sli), cap(sli), sli) + + //删除尾部两个元素 + sli_7 := sli[:len(sli)-2] + fmt.Printf("len=%d cap=%d slice=%v\n", len(sli_7), cap(sli_7), sli_7) + //删除开头两个元素 + sli_8 := sli[2:] + fmt.Printf("len=%d cap=%d slice=%v\n", len(sli_8), cap(sli_8), sli_8) + //删除中间 2 个元素 + sli_9 := append(sli[:3], sli[5:]...) + fmt.Printf("len=%d cap=%d slice=%v\n", len(sli_9), cap(sli_9), sli_9) +} diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo5/demo5.go" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo5/demo5.go" new file mode 100644 index 0000000000000000000000000000000000000000..953b2c7abfa4d2274742bfd8628e98fc11de013a --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo5/demo5.go" @@ -0,0 +1,43 @@ +package main + +import ( + "flag" + "fmt" +) + +// 定义命令行参数 +var mode = flag.String("mode", "say yes!!", "fast模式能让程序运行的更快") + +func main() { + // 指针示例 + var a int = 1010 + var ptr = &a + + fmt.Printf("%p\n", &a) + + fmt.Printf("%T %p\n", ptr, ptr) + fmt.Println("指针地址代表的值", *ptr) + // 指针换值 + var num1 = 10 + modifyFromPoint(num1) + fmt.Println("未使用指针,方法外", num1) + + var num2 = 20 + newModifyFromPoint(&num2) + fmt.Println("未使用指针,方法外", num2) + // new方法声明指针 + str := new(string) + *str = "hello" + fmt.Println("new方法声明指针:", *str) + + flag.Parse() + fmt.Println(*mode) +} + +func modifyFromPoint(num int) { + num = 1000 +} + +func newModifyFromPoint(ptr *int) { + *ptr = 1000 +} diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo6/demo6.go" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo6/demo6.go" new file mode 100644 index 0000000000000000000000000000000000000000..6bb3d5f8b382c0acee9b05a4359d64bbd37ab1f0 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo6/demo6.go" @@ -0,0 +1,19 @@ +package main + +var global *int + +func main() { + f() + + g() +} + +func f() { + var x int + x = 1 + global = &x +} +func g() { + y := new(int) + *y = 1 +} diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo7/demo7.go" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo7/demo7.go" new file mode 100644 index 0000000000000000000000000000000000000000..13568ade4a02b341798b11c300fee9c92f352884 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo7/demo7.go" @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" +) + +// 将NewInt定义为int类型 +type NewInt int + +// 将int取一个别名叫IntAlias +type IntAlias = int + +func main() { + // 将a声明为NewInt类型 + var a1 NewInt + // 查看a的类型名 main.NewInt + fmt.Printf("a1 type: %T\n", a1) + // 将a2声明为IntAlias类型 + var a2 IntAlias + // 查看a2的类型名 int + //IntAlias 类型只会在代码中存在,编译完成时,不会有 IntAlias 类型。 + fmt.Printf("a2 type: %T\n", a2) +} diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo8/demo8.go" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo8/demo8.go" new file mode 100644 index 0000000000000000000000000000000000000000..01520909baf6f6a7509b326d8ce11a5227c3c567 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo8/demo8.go" @@ -0,0 +1,29 @@ +package main + +import ( + "fmt" + "strconv" +) + +func main() { + // str 转 int + newStr1 := "1" + intValue, _ := strconv.Atoi(newStr1) + fmt.Printf("%T,%d\n", intValue, intValue) + + // int 转 str + intValue2 := 2 + strValue := strconv.Itoa(intValue2) + fmt.Printf("%T,%s\n", strValue, strValue) + + // str 转 float + string3 := "3.1415926" + f, _ := strconv.ParseFloat(string3, 64) + fmt.Printf("%T, %f\n", f, f) + + //float 转 string + floatValue := 3.1415926 + formatFloat := strconv.FormatFloat(floatValue, 'f', 8, 64) + fmt.Printf("%T,%s", formatFloat, formatFloat) + +} diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo9/demo9.go" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo9/demo9.go" new file mode 100644 index 0000000000000000000000000000000000000000..25d88ba62db75b77b7505b0a05b08460d286bb7f --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/demo9/demo9.go" @@ -0,0 +1,35 @@ +package main + +import "fmt" + +func main() { + //map声明 + var mapLit map[string]int + var mapVal map[string]int + + mapLit = map[string]int{"a": 1, "b": 2, "c": 3} + mapVal = mapLit + //mapVal 是 mapList 的引用 + mapVal["c"] = 4 + + fmt.Printf("Map literal at \"a\" is: %d\n", mapLit["a"]) + fmt.Printf("Map literal at \"b\" is: %d\n", mapVal["b"]) + fmt.Printf("Map literal at \"c\" is: %d\n", mapLit["c"]) + + //循环遍历 + scene := make(map[string]int, 10) + scene["dog"] = 11 + scene["cat"] = 20 + scene["pig"] = 30 + + for k, v := range scene { + fmt.Printf("name:%s,num:%d\n", k, v) + } + fmt.Println() + //删除 + delete(scene, "cat") + for k, v := range scene { + fmt.Printf("name:%s,num:%d\n", k, v) + } + +} diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/go.mod" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/go.mod" new file mode 100644 index 0000000000000000000000000000000000000000..bfdb7d531a2da5d48132b3a87f9814e6e88b2116 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/code/go.mod" @@ -0,0 +1,3 @@ +module code + +go 1.17 diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/1.\344\270\213\350\275\275\344\270\216\347\216\257\345\242\203\345\217\230\351\207\217\351\205\215\347\275\256.md" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/1.\344\270\213\350\275\275\344\270\216\347\216\257\345\242\203\345\217\230\351\207\217\351\205\215\347\275\256.md" new file mode 100644 index 0000000000000000000000000000000000000000..66a66c45c7b8c059f45a3ad6b4cb73608b11546d --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/1.\344\270\213\350\275\275\344\270\216\347\216\257\345\242\203\345\217\230\351\207\217\351\205\215\347\275\256.md" @@ -0,0 +1,62 @@ +## 目标 +1. 安装完成 + +2. 成功运行hello world + +## Go下载安装 + + 官方二进制发行版可在[https://go.dev/dl/] + + 下载二进制版本后,请访问[https://go.dev/doc/install] + + 如果二进制发行版不适用于您的操作系统和体系结构组合,请访问[https://go.dev/doc/install/source] + +## 环境变量配置 +1. GOROOT:go语言所在的目录,用于全局执行go相关的命令 +![img.png](goroot.png) + path中也需要配置 +![img_1.png](PATH.png) +2. GOPATH:工作目录,工程代码存放的位置,此目录下,一个文件夹就是一个工程 +![img.png](GOPATH.png) +3. GOPROXY:代理,由于go需要翻墙使用,需要配置代理 +![img.png](GOPROXY.png) + 地址:https://goproxy.io/zh/ 可以去看文档 +4. 检查环境变量的配置是否正确 + + `使用命令行执行:go env` +![img.png](配置.png) + + +## hello world + +1. 在路径下,新建一个文件夹hello,进入这个文件夹 +2. 运行命令: go mod init hello + ![img.png](mod.png) +3. 生成mod文件,如果学过maven的话,可以将其当成maven的pom.xml,用于管理依赖的 + ![img_1.png](mod_2.png) + +4. 新建main.go,输入以下内容: + + // package 定义包名 main 包名 + package main + + // import 引用库 fmt 库名 + import "fmt" + + // func 定义函数 main 函数名 + func main() { + + // fmt 包名 . 调用 Print 函数,并且输出定义的字符串 + fmt.Print("Hello World!!") + } +5. 执行命令:go run main.go + ![img.png](执行.png) + +## 开发工具 + + GoLand 是 JetBrains 公司推出的 Go 语言集成开发环境, + 与我们用的 WebStorm、PhpStorm、PyCharm 是一家,同样支持 Windows、Linux、macOS 等操作系统。 + + 下载地址:https://www.jetbrains.com/go/ + + 软件是付费的,不过想想办法,软件可以永久激活的。 diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/10.nil.md" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/10.nil.md" new file mode 100644 index 0000000000000000000000000000000000000000..3c68c21aa59c6de32820be263e06f7ae077c5dd3 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/10.nil.md" @@ -0,0 +1,100 @@ +## 概述 +在Go语言中,布尔类型的零值(初始值)为 false,数值类型的零值为 0,字符串类型的零值为空字符串`""`,而指针、切片、映射、通道、函数和接口的零值则是 nil。 + +**nil 标识符不能比较** + + package main + import ( + "fmt" + ) + + func main() { + //invalid operation: nil == nil (operator == not defined on nil) + fmt.Println(nil==nil) + } + +**nil 不是关键字或保留字** + + //不提倡这样做 + var nil = errors.New("my god") + +**nil 没有默认类型** + + package main + import ( + "fmt" + ) + + func main() { + //error :use of untyped nil + fmt.Printf("%T", nil) + print(nil) + } + +**不同类型 nil 的指针是一样的** + + package main + import ( + "fmt" + ) + + func main() { + var arr []int + var num *int + fmt.Printf("%p\n", arr) + fmt.Printf("%p", num) + } + +**nil 是 map、slice、pointer、channel、func、interface 的零值** + + package main + import ( + "fmt" + ) + + func main() { + var m map[int]string + var ptr *int + var c chan int + var sl []int + var f func() + var i interface{} + + fmt.Printf("%#v\n", m) + fmt.Printf("%#v\n", ptr) + fmt.Printf("%#v\n", c) + fmt.Printf("%#v\n", sl) + fmt.Printf("%#v\n", f) + fmt.Printf("%#v\n", i) + } + +**不同类型的 nil 值占用的内存大小可能是不一样的** + + package main + import ( + "fmt" + "unsafe" + ) + + func main() { + var p *struct{} + fmt.Println( unsafe.Sizeof( p ) ) // 8 + var s []int + fmt.Println( unsafe.Sizeof( s ) ) // 24 + var m map[int]bool + fmt.Println( unsafe.Sizeof( m ) ) // 8 + var c chan string + fmt.Println( unsafe.Sizeof( c ) ) // 8 + var f func() + fmt.Println( unsafe.Sizeof( f ) ) // 8 + var i interface{} + fmt.Println( unsafe.Sizeof( i ) ) // 16 + } + +## new和make + +make 关键字的主要作用是创建 slice、map 和 Channel 等内置的数据结构,而 new 的主要作用是为类型申请一片内存空间,并返回指向这片内存的指针。 + +1. make 分配空间后,会进行初始化,new分配的空间被清零 +2. new 分配返回的是指针,即类型 *Type。make 返回引用,即 Type; +3. new 可以分配任意类型的数据; \ No newline at end of file diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/11.\345\205\263\351\224\256\345\255\227.md" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/11.\345\205\263\351\224\256\345\255\227.md" new file mode 100644 index 0000000000000000000000000000000000000000..ed4acdd14289cf0ad74aa949fcfce1542ba0c243 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/11.\345\205\263\351\224\256\345\255\227.md" @@ -0,0 +1,415 @@ +## if else +关键字` if `是用于测试某个条件(布尔型或逻辑型)的语句,如果该条件成立,则会执行 if 后由大括号`{}`括起来的代码块,否则就忽略该代码块继续执行后续的代码。 + + if condition { + // 条件为真 执行 + } else { + // 条件不满足 执行 + } + +如果存在第三个分支,则可以使用下面这种三个独立分支的形式: + + if condition1 { + // condition1 满足 执行 + } else if condition2 { + // condition1 不满足 condition2满足 执行 + }else { + // condition1和condition2都不满足 执行 + } + +**if语句可以嵌套** + + /* 定义局部变量 */ + var a int = 100 + var b int = 200 + + /* 判断条件 */ + if a == 100 { + /* if 条件语句为 true 执行 */ + if b == 200 { + /* if 条件语句为 true 执行 */ + fmt.Printf("a 的值为 100 , b 的值为 200\n" ) + } + } + +### 特殊写法 + +if 还有一种特殊的写法,可以在 if 表达式之前添加一个执行语句,再根据变量值进行判断: + + if a := 10; a >5 { + fmt.Println(a) + return + } + +## for + +**go语言中的循环语句只支持 for 关键字** + +第一种写法: + + sum := 0 + //i := 0; 赋初值,i<10 循环条件 如果为真就继续执行 ;i++ 后置执行 执行后继续循环 + for i := 0; i < 10; i++ { + sum += i + } + +第二种写法: + + sum := 0 + for { + sum++ + if sum > 100 { + //break是跳出循环 + break + } + } + +第三种写法: + + n := 10 + for n>0 { + n-- + fmt.Println(n) + } + +特殊写法: + + step := 2 + //初值可以省略,但是;必须有,但是这样写step的作用域就比较大了,脱离了for循环 + for ; step > 0; step-- { + fmt.Println(step) + } + +**结束循环的方式:** + +1.return + + step := 2 + for step > 0 { + step-- + fmt.Println(step) + //执行一次就结束了 + return + } + //不会执行 + fmt.Println("结束之后的语句....") + +2.break + + step := 2 + for step > 0 { + step-- + fmt.Println(step) + //跳出循环,还会继续执行循环外的语句 + break + } + //会执行 + fmt.Println("结束之后的语句....") + +3.painc + + step := 2 + for step > 0 { + step-- + fmt.Println(step) + //报错了,直接结束 + panic("出错了") + } + //不会执行 + fmt.Println("结束之后的语句....") + +4.goto + + package main + import "fmt" + func main() { + for x := 0; x < 10; x++ { + for y := 0; y < 10; y++ { + if y == 2 { + // 跳转到标签 + goto breakHere + } + } + } + // 手动返回, 避免执行进入标签 + return + // 标签 + breakHere: + fmt.Println("done") + } + +### 九九乘法表 + + package main + import "fmt" + func main() { + // 遍历, 决定处理第几行 + for y := 1; y <= 9; y++ { + // 遍历, 决定这一行有多少列 + for x := 1; x <= y; x++ { + fmt.Printf("%d*%d=%d ", x, y, x*y) + } + // 手动生成回车 + fmt.Println() + } + } + +## for range +for range 结构是Go语言特有的一种的迭代结构,for range 可以遍历数组、切片、字符串、map 及管道(channel) + + for key, val := range coll { + ... + } + +遍历map: + + m := map[string]int{ + "hello": 100, + "world": 200, + } + for key, value := range m { + fmt.Println(key, value) + } + +字符串也可以: + + str := "你好go" + //因为一个字符串是 Unicode 编码的字符(或称之为 rune )集合 + //char 实际类型是 rune 类型 + for pos, char := range str { + fmt.Println(pos,char) + } + +通过 for range 遍历的返回值有一定的规律: + +- 数组、切片、字符串返回索引和值。 +- map 返回键和值。 +- channel只返回管道内的值。 + + +## switch + +switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止。 + +switch 分支表达式可以是任意类型,不限于常量。可省略 break,默认自动终止。 + +switch 语句的语法: + + switch var1 { + case val1: + ... + case val2: + ... + default: + ... + } + +### 例: + /* 定义局部变量 */ + var grade string = "B" + var score int = 90 + + switch score { + case 90: grade = "A" + case 80: grade = "B" + case 50,60,70 : grade = "C" + default: grade = "D" + } + //swtich后面如果没有条件表达式,则会对true进行匹配 + switch { + case grade == "A" : + fmt.Printf("优秀!\n" ) + case grade == "B", grade == "C" : + fmt.Printf("良好\n" ) + case grade == "D" : + fmt.Printf("及格\n" ) + case grade == "F": + fmt.Printf("不及格\n" ) + default: + fmt.Printf("差\n" ) + } + fmt.Printf("你的等级是 %s\n", grade ) + + +**fallthrough** + + var s = "hello" + switch { + case s == "hello": + fmt.Println("hello") + fallthrough + case s != "world": + fmt.Println("world") + } + +**加了fallthrough后,会直接运行【紧跟的后一个】case或default语句,不论条件是否满足都会执行。** + +## goto + +goto 语句通过标签进行代码间的无条件跳转,同时 goto 语句在快速跳出循环、避免重复退出上也有一定的帮助,使用 goto 语句能简化一些代码的实现过程。 + +传统写法: + + package main + import "fmt" + func main() { + var breakAgain bool + // 外循环 + for x := 0; x < 10; x++ { + // 内循环 + for y := 0; y < 10; y++ { + // 满足某个条件时, 退出循环 + if y == 2 { + // 设置退出标记 + breakAgain = true + // 退出本次循环 + break + } + } + // 根据标记, 还需要退出一次循环 + if breakAgain { + break + } + } + fmt.Println("done") + } + +使用goto的写法: + + package main + import "fmt" + func main() { + for x := 0; x < 10; x++ { + for y := 0; y < 10; y++ { + if y == 2 { + // 跳转到标签 + goto breakHere + } + } + } + // 手动返回, 避免执行进入标签 + return + // 标签 + breakHere: + fmt.Println("done") + } + +**使用 goto 集中处理错误** + +多处错误处理 `存在代码重复` 例如: + + package main + import ( + "errors" + "fmt" + "os" + ) + + func main() { + err := firstCheckError() + if err != nil { + fmt.Println(err) + exitProcess() + } + err = secondCheckError() + if err != nil { + fmt.Println(err) + exitProcess() + } + fmt.Println("done") + } + + func secondCheckError() interface{} { + return errors.New("错误2") + } + + func exitProcess() { + //退出 + os.Exit(1) + } + + func firstCheckError() interface{} { + return errors.New("错误1") + } + +使用goto: + + package main + import ( + "errors" + "fmt" + "os" + ) + + func main() { + err := firstCheckError() + if err != nil { + fmt.Println(err) + goto onExit + } + err = secondCheckError() + if err != nil { + fmt.Println(err) + goto onExit + } + fmt.Println("done") + return + onExit: + exitProcess() + } + + func secondCheckError() interface{} { + return errors.New("错误2") + } + + func exitProcess() { + fmt.Println("exit") + //退出 + os.Exit(1) + } + + func firstCheckError() interface{} { + return errors.New("错误1") + } + +## break +break 语句可以结束 for、switch 和 select 的代码块,另外 break 语句还可以在语句后面添加`标签`,表示退出某个标签对应的代码块,`标签`要求必须定义在对应的 `for`、`switch` 和 `select `的代码块上。 + +### 例: + + package main + import "fmt" + func main() { + OuterLoop: + for i := 0; i < 2; i++ { + for j := 0; j < 5; j++ { + switch j { + case 2: + fmt.Println(i, j) + break OuterLoop + case 3: + fmt.Println(i, j) + break OuterLoop + } + } + } + } + +## continue + +continue 语句可以结束当前循环,开始下一次的循环迭代过程,仅限在 for 循环内使用,在 continue 语句后添加`标签`时,表示开始`标签对应的循环` + + package main + import "fmt" + func main() { + OuterLoop: + for i := 0; i < 2; i++ { + for j := 0; j < 5; j++ { + switch j { + case 2: + fmt.Println(i, j) + continue OuterLoop + } + } + } + } \ No newline at end of file diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/12.\345\207\275\346\225\260.md" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/12.\345\207\275\346\225\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..e228574f50f65fb3ff0a9fc7004163bbcbac7f9a --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/12.\345\207\275\346\225\260.md" @@ -0,0 +1,276 @@ +## 函数 +Go 语言支持普通函数、匿名函数和闭包,从设计上对函数进行了优化和改进,让函数使用起来更加方便。 + +Go 语言的函数属于“一等公民”(first-class),也就是说: + +- 函数本身可以作为值进行传递。 +- 支持匿名函数和闭包(closure)。 +- 函数可以满足接口。 + +**函数定义:** + + func function_name( [parameter list] ) [return_types] { + 函数体 + } + +**示例:** + + package main + + import "fmt" + + func main() { + fmt.Println(max(1, 10)) + fmt.Println(max(-1, -2)) + } + //类型相同的相邻参数,参数类型可合并。 + func max(n1, n2 int) int { + if n1 > n2 { + return n1 + } + return n2 + } + +**返回值可以为多个:** + + func test(x, y int, s string) (int, string) { + // 类型相同的相邻参数,参数类型可合并。 多返回值必须用括号。 + n := x + y + return n, fmt.Sprintf(s, n) + } + +### 1.函数作为参数 + +**例:** + + func test(fn func() int) int { + return fn() + } + func fn() int{ + return 200 + } + func main() { + //这是直接使用匿名函数 + s1 := test(func() int { return 100 }) + //这是传入一个函数 + s1 := test(fn) + fmt.Println(s1) + } + +**在将函数做为参数的时候,我们可以使用类型定义,将函数定义为类型,这样便于阅读** + + // 定义函数类型。 + + type FormatFunc func(s string, x, y int) string + + func format(fn FormatFunc, s string, x, y int) string { + return fn(s, x, y) + } + func formatFun(s string,x,y int) string { + return fmt.Sprintf(s,x,y) + } + func main() { + s2 := format(formatFun,"%d, %d",10,20) + fmt.Println(s2) + } + +**有返回值的函数,必须有明确的终止语句** + +### 2. 函数返回值 + +函数返回值可以有多个,同时Go支持对返回值命名 + +**例:** + + //多个返回值 用括号扩起来 + func sum(a,b int) (int,int) { + return a,b + } + func main(){ + a,b := sum(2,3) + fmt.Println(a,b) + } + + + package main + + import "fmt" + //支持返回值命名 ,默认值为类型零值,命名返回参数可看做与形参类似的局部变量, + 由return隐式返回 + func f1() (names []string, m map[string]int, num int) { + m = make(map[string]int) + m["k1"] = 2 + + return + } + + func main() { + a, b, c := f1() + fmt.Println(a, b, c) + } + +### 3. 参数 +函数定义时指出,函数定义时有参数,该变量可称为函数的形参。 + +函数可以通过两种方式来传递参数: + +1.值传递:指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。 + + func swap(x, y int) int { + ... ... + } + +2.引用传递:是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。 + + package main + + import ( + "fmt" + ) + + /* 定义相互交换值的函数 */ + func swap(x, y *int) { + *x,*y = *y,*x + } + + func main() { + var a, b int = 1, 2 + /* + 调用 swap() 函数 + &a 指向 a 指针,a 变量的地址 + &b 指向 b 指针,b 变量的地址 + */ + swap(&a, &b) + + fmt.Println(a, b) + } + +**不定参数传值** + +不定参数传值就是函数的参数不是固定的,后面的类型是固定的(可变参数)。 + +在参数赋值时可以不用用一个一个的赋值,可以直接传递一个数组或者切片。 + +格式: + + func myfunc(args ...int) { //0个或多个参数 + } + + func add(a int, args…int) int { //1个或多个参数 + } + + func add(a int, b int, args…int) int { //2个或多个参数 + } + +**注意:其中args是一个slice,我们可以通过arg[index]依次访问所有参数,通过len(arg)来判断传递参数的个数.** + +**例:** + + package main + + import ( + "fmt" + ) + + func test(s string, n ...int) string { + var x int + for _, i := range n { + x += i + } + return fmt.Sprintf(s, x) + } + + func main() { + s := []int{1, 2, 3} + res := test("sum: %d", s...) // slice... 展开slice + println(res) + } + +## 匿名函数 + +### 概述 +匿名函数是指不需要定义函数名的一种函数实现方式。 + +匿名函数由一个不带函数名的函数声明和函数体组成。匿名函数的优越性在于可以直接使用函数内的变量,不必声明。 + +匿名函数的定义格式: + + func(参数列表)(返回参数列表){ + 函数体 + } + +**例:** + + package main + + import ( + "fmt" + "math" + ) + + func main() { + //这里将一个函数当做一个变量一样的操作。 + getSqrt := func(a float64) float64 { + return math.Sqrt(a) + } + fmt.Println(getSqrt(4)) + } + +**在定义时调用匿名函数** + +**例:** + + func(data int) { + fmt.Println("hello", data) + }(100) //(100),表示对匿名函数进行调用,传递参数为 100。 + +**匿名函数用作回调函数** + +**例:** + + package main + import ( + "fmt" + ) + // 遍历切片的每个元素, 通过给定函数进行元素访问 + func visit(list []int, f func(int)) { + for _, v := range list { + f(v) + } + } + func main() { + // 使用匿名函数打印切片内容 + visit([]int{1, 2, 3, 4}, func(v int) { + fmt.Println(v) + }) + } + +**返回多个匿名函数** + +**例:** + + package main + + import "fmt" + + func FGen(x, y int) (func() int, func(int) int) { + + //求和的匿名函数 + sum := func() int { + return x + y + } + + // (x+y) *z 的匿名函数 + avg := func(z int) int { + return (x + y) * z + } + return sum, avg + } + + func main() { + + f1, f2 := FGen(1, 2) + fmt.Println(f1()) + fmt.Println(f2(3)) + } + diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/2.\345\217\230\351\207\217\345\270\270\351\207\217.md" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/2.\345\217\230\351\207\217\345\270\270\351\207\217.md" new file mode 100644 index 0000000000000000000000000000000000000000..5626697b014f713a12ae5f7949e9207ba3949104 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/2.\345\217\230\351\207\217\345\270\270\351\207\217.md" @@ -0,0 +1,125 @@ +## 数据类型 +这篇文章主要涉及 字符串、布尔、数字 + +### 1.字符串:string +只能用一对双引号("")或反引号(``)括起来定义,不能用单引号('')定义! + +go语言从底层就支持UTF-8编码。 + + var mystr string = "hello" + +字符串是字节的定长数组,byte 和 rune 都是字符类型,若多个字符放在一起,就组成了字符串 + + import ( + "fmt" + ) + + func main() { + var mystr01 string = "hello" + var mystr02 [5]byte = [5]byte{104, 101, 108, 108, 111} + fmt.Printf("myStr01: %s\n", mystr01) + fmt.Printf("myStr02: %s", mystr02) + } + +### 2.布尔:bool + var 变量名 bool +只有 true 和 false,默认为 false。 + +### 3.数字 +#### 3.1 整型 + + - 有符号整型:int、int8、int64、int32、int64 范围:-2^(n-1) 到 2^(n-1)-1 + - 无符号整型:uint、uint8、uint64、uint32、uint64、uintptr 范围: 0 到 2^n-1 + + 具体长度取决于 CPU 位数。 + +#### 3.2 浮点型 + + float32 float64 + **通常应该优先使用 float64 类型 + +## 4.字符型 + + - 一种是 uint8 类型,或者叫 byte 型,代表了 ASCII 码的一个字符。 + - 另一种是 rune 类型,代表一个 UTF-8 字符,当需要处理中文、日文或者其他复合字符时,则需要用到 rune 类型。 + rune 类型等价于 int32 类型。 + +### byte 类型是 uint8 的别名,rune 类型是int32的别名 + + //使用单引号 表示一个字符 + var ch byte = 'A' + //在 ASCII 码表中,A 的值是 65,也可以这么定义 + var ch byte = 65 + //65使用十六进制表示是41,所以也可以这么定义 \x 总是紧跟着长度为 2 的 16 进制数 + var ch byte = '\x41' + //65的八进制表示是101,所以使用八进制定义 \后面紧跟着长度为 3 的八进制数 + var ch byte = '\101' + + fmt.Printf("%c",ch) + +## 变量声明 + 一、单个变量声明 + + 1.var 变量名称 数据类型 = 变量值 + + 如果不赋值,使用的是该数据类型的默认值。 + + 2.var 变量名称 = 变量值 + + 根据变量值,自行判断数据类型。 + + 3.变量名称 := 变量值 + + 省略了 var 和数据类型,变量名称一定要是未声明过的。 + + 二、多个变量声明 + + 1.var 变量名称,变量名称 ... ,数据类型 = 变量值,变量值 ... + + 2.var 变量名称,变量名称 ... = 变量值,变量值 ... + + 3.变量名称,变量名称 ... := 变量值,变量值 ... + +## 常量声明 + 常量,在程序编译阶段就确定下来的值,而程序在运行时无法改变该值。 + + 一、单个常量声明 + + 1.const 变量名称 数据类型 = 变量值 + + 如果不赋值,使用的是该数据类型的默认值。 + + 2.const 变量名称 = 变量值 + + 根据变量值,自行判断数据类型。 + + 二、多个常量声明 + + 1.const 变量名称,变量名称 ... ,数据类型 = 变量值,变量值 ... + + 2.const 变量名称,变量名称 ... = 变量值,变量值 ... + + 三、常量生成器iota + + 在一个 const 声明语句中,在第一个声明的常量所在的行,iota 将会被置为 0,然后在每一个有常量声明的行加1 + + 例: + + const ( + Sunday = iota //0 + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday //6 + ) + +## 输出方法 + fmt.Print:输出到控制台(仅只是输出) + + fmt.Println:输出到控制台并换行 + + fmt.Printf:仅输出格式化的字符串和字符串变量(整型和整型变量不可以) + + fmt.Sprintf:格式化并返回一个字符串,不输出。 \ No newline at end of file diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/3.\346\225\260\347\273\204.md" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/3.\346\225\260\347\273\204.md" new file mode 100644 index 0000000000000000000000000000000000000000..ab3840519781d6300e351065491f6b2ea8817759 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/3.\346\225\260\347\273\204.md" @@ -0,0 +1,33 @@ +## 数组 + 数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成, +声明后数组的长度就固定了,不能动态变化。 + +注: +len() 和 cap() 返回结果始终一样。 + +## 声明数组 + +一维数组: + + var arr_1 [5] int + + var arr_2 = [5] int {1, 2, 3, 4, 5} + + arr_3 := [5] int {1, 2, 3, 4, 5} + + arr_4 := [...] int {1, 2, 3, 4, 5, 6} + + arr_5 := [5] int {0:3, 1:5, 4:6} + +二维数组: + + var arr_6 = [3][5] int {{1, 2, 3, 4, 5}, {9, 8, 7, 6, 5}, {3, 4, 5, 6, 7}} + + arr_7 := [3][5] int {{1, 2, 3, 4, 5}, {9, 8, 7, 6, 5}, {3, 4, 5, 6, 7}} + + arr_8 := [...][5] int {{1, 2, 3, 4, 5}, {9, 8, 7, 6, 5}, {0:3, 1:5, 4:6}} + +## 注意事项 +#### 一、数组不可动态变化问题,一旦声明了,长度固定,不能添加。 +#### 二、数组是值类型问题,在函数中传递值的时候,如果传递数组大,内存耗损大。 +#### 三、数组赋值问题,同样类型的数组(长度一样且每个元素类型也一样)才可以相互赋值,反之不可以。 \ No newline at end of file diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/4.\345\210\207\347\211\207.md" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/4.\345\210\207\347\211\207.md" new file mode 100644 index 0000000000000000000000000000000000000000..c8b1f8260a910dd14be48c8191adf3d445600e20 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/4.\345\210\207\347\211\207.md" @@ -0,0 +1,69 @@ +## 切片 +切片是一种动态数组,比数组操作灵活,长度不固定,可以进行追加和删除。 + +注: +len() 和 cap() 返回结果可相同和不同。 + +## 切片声明 + + var sli_1 [] int //nil 切片 + + var sli_2 = [] int {} //空切片 + + var sli_3 = [] int {1, 2, 3, 4, 5} + + sli_4 := [] int {1, 2, 3, 4, 5} + + var sli_5 [] int = make([] int, 5, 8) + + sli_6 := make([] int, 5, 9) + +## 截取切片 + + sli := [] int {1, 2, 3, 4, 5, 6} + + fmt.Println("sli[1] ==", sli[1]) + fmt.Println("sli[:] ==", sli[:]) + fmt.Println("sli[1:] ==", sli[1:]) + fmt.Println("sli[:4] ==", sli[:4]) + + fmt.Println("sli[0:3] ==", sli[0:3]) //左闭右开 + fmt.Println("sli[0:3:4] ==", sli[0:3:4]) + +## 追加切片 + + sli := [] int {4, 5, 6} + + sli = append(sli, 7) + sli = append(sli, 8) + sli = append(sli, 9) + sli = append(sli, 10) + +注: +append 时,切片声明容量不够需要扩容时,cap 会翻倍。 + +## 删除切片 + + sli := [] int {1, 2, 3, 4, 5, 6, 7, 8} + + //删除尾部两个元素 + sli[:len(sli)-2] + //删除开头两个元素 + sli[2:] + //删除中间 2 个元素 + sli = append(sli[:3], sli[3+2:]...) + +## 切片复制 + +copy() 函数的使用格式: + + copy( destSlice, srcSlice []T) int + +### 例: + slice1 := []int{1, 2, 3, 4, 5} + slice2 := []int{5, 4, 3} + copy(slice2, slice1) // 只会复制slice1的前3个元素到slice2中 + copy(slice1, slice2) // 只会复制slice2的3个元素到slice1的前3个位置 + + + diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/5.\346\214\207\351\222\210.md" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/5.\346\214\207\351\222\210.md" new file mode 100644 index 0000000000000000000000000000000000000000..e9c65c64ab73ecb909003ef5f0238cc2d8960a5e --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/5.\346\214\207\351\222\210.md" @@ -0,0 +1,85 @@ +## 概述 +指针(pointer)在Go语言中可以被拆分为两个核心概念: + +- 类型指针,允许对这个指针类型的数据进行修改、传递数据,无须拷贝数据,类型指针不能进行偏移和运算。 +- 切片,由指向起始元素的原始指针、元素数量和容量组成。 + +### 1、 如何理解指针 + + var a int = 10 +在内存中开辟了一片空间,空间内存放着数值10,这片空间在整个内存当中,有一个唯一的地址,用来进行标识, +指向这个地址的变量就称为指针 + +当一个指针被定义,没有分配到任何变量时,它的默认值为 nil。 + +Go语言中使用在变量名前面添加`&`操作符(前缀)来获取变量的内存地址(取地址操作) + + //v 代表被取地址的变量,变量 v 的地址使用变量 ptr 进行接收,ptr 的类型为*T,称做 T 的指针类型,*代表指针。 + ptr := &v + +当使用`&`操作符对普通变量进行取地址操作并得到变量的指针后,可以对指针使用`*`操作符,也就是指针取值 + + // 指针与变量 + var room int = 10 // room房间 里面放的 变量10 + var ptr = &room // 门牌号px 指针 0xc00000a0a8 + + fmt.Printf("%p\n", &room) // 变量的内存地址 0xc00000a0a8 + + fmt.Printf("%T, %p\n", ptr, ptr) // *int, 0xc00000a0a8 + + fmt.Println("指针地址",ptr) // 0xc00000a0a8 + fmt.Println("指针地址代表的值", *ptr) // 10 + +### 2、 使用指针修改值 + + func main(){ + // 利用指针修改值 + var num = 10 + modifyFromPoint(num) + fmt.Println("未使用指针,方法外",num) + + var num2 = 22 + newModifyFromPoint(&num2) // 传入指针 + fmt.Println("使用指针 方法外",num2) + } + + func modifyFromPoint(num int) { + // 未使用指针 + num = 10000 + fmt.Println("未使用指针,方法内:",num) + } + + func newModifyFromPoint(ptr *int) { + // 使用指针 + *ptr = 1000 // 修改指针地址指向的值 + fmt.Println("使用指针,方法内:",*ptr) + } + +### 3、 创建指针的另一种方法 + + new(类型) + +new() 函数可以创建一个对应类型的指针,创建过程会分配内存,被创建的指针指向默认值。 + + str := new(string) + *str = "hello" + fmt.Println(*str) + +### 4、 指针小案例 + +Go语言内置的 flag 包实现了对命令行参数的解析,flag 包使得开发命令行工具更为简单。 + + package main + // 导入系统包 + import ( + "flag" + "fmt" + ) + // 定义命令行参数 + var mode = flag.String("mode", "", "fast模式能让程序运行的更快") + + func main() { + // 解析命令行参数 + flag.Parse() + fmt.Println(*mode) + } \ No newline at end of file diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/6.\345\217\230\351\207\217\347\232\204\347\224\237\345\221\275\345\221\250\346\234\237.md" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/6.\345\217\230\351\207\217\347\232\204\347\224\237\345\221\275\345\221\250\346\234\237.md" new file mode 100644 index 0000000000000000000000000000000000000000..73d62ae9d9ad6b410568ce8ecfd27ae330ab963d --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/6.\345\217\230\351\207\217\347\232\204\347\224\237\345\221\275\345\221\250\346\234\237.md" @@ -0,0 +1,39 @@ +## 概述 + + 变量的生命周期指的是在程序运行期间变量有效存在的时间间隔。 + +变量的生命周期与变量的作用域有不可分割的联系: + +1. 全局变量:它的生命周期和整个程序的运行周期是一致的; +2. 局部变量:它的生命周期则是动态的,从创建这个变量的声明语句开始,到这个变量不再被引用为止; +3. 形式参数和函数返回值:它们都属于局部变量,在函数被调用的时候创建,函数调用结束后被销毁。 + + +go的内存中应用了两种数据结构用于存放变量: + +1. 堆(heap):堆是用于存放进程执行中被动态分配的内存段。它的大小并不固定,可动态扩张或缩减。当进程调用 malloc 等函数分配内存时, +新分配的内存就被动态加入到堆上(堆被扩张)。当利用 free 等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减); +2. 栈(stack):栈又称堆栈, 用来存放程序暂时创建的局部变量,也就是我们函数的大括号`{ }`中定义的局部变量。 + + + 栈是先进后出,往栈中放元素的过程,称为入栈,取元素的过程称为出栈。 + 栈可用于内存分配,栈的分配和回收速度非常快 + + +### 例: + + var global *int + func f() { + var x int + x = 1 + global = &x + } + func g() { + y := new(int) + *y = 1 + } + +上述代码中,函数 f 里的变量 x 必须在堆上分配,因为它在函数退出后依然可以通过包一级的 global 变量找到,虽然它是在函数内部定义的。 + +相反,当函数 g 返回时,变量 y 不再被使用,也就是说可以马上被回收的。因此,y 并没有从函数 g 中逃逸,编译器可以选择在栈上分配 *y 的存储空间, +也可以选择在堆上分配,然后由Go语言的 GC(垃圾回收机制)回收这个变量的内存空间。 \ No newline at end of file diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/7.\347\261\273\345\236\213\345\210\253\345\220\215\343\200\201\345\205\263\351\224\256\345\255\227.md" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/7.\347\261\273\345\236\213\345\210\253\345\220\215\343\200\201\345\205\263\351\224\256\345\255\227.md" new file mode 100644 index 0000000000000000000000000000000000000000..5ed8bbb9a339f0ee0b43d49234976376e6dc5958 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/7.\347\261\273\345\236\213\345\210\253\345\220\215\343\200\201\345\205\263\351\224\256\345\255\227.md" @@ -0,0 +1,73 @@ +## 类型别名 + + 类型别名是 Go 1.9 版本添加的新功能, + 主要用于解决代码升级、迁移中存在的类型兼容性问题。 + +别名格式: + + //TypeAlias 只是 Type 的别名,本质上 TypeAlias 与 Type 是同一个类型 + type TypeAlias = Type + +类型定义: + + //定义Name为Type类型 ,定义之后 Name为一种新的类型 + type Name Type + +类型别名和类型定义的区别: + + package main + import ( + "fmt" + ) + // 将NewInt定义为int类型 + type NewInt int + // 将int取一个别名叫IntAlias + type IntAlias = int + + func main() { + // 将a声明为NewInt类型 + var a NewInt + // 查看a的类型名 main.NewInt + fmt.Printf("a type: %T\n", a) + // 将a2声明为IntAlias类型 + var a2 IntAlias + // 查看a2的类型名 int + //IntAlias 类型只会在代码中存在,编译完成时,不会有 IntAlias 类型。 + fmt.Printf("a2 type: %T\n", a2) + } + +## 关键字 + +Go语言中的关键字一共有 25 个: + +![img.png](关键字.png) + +## 标识符 + +标识符是指Go语言对各种变量、方法、函数等命名时使用的字符序列,标识符由若干个字母、下划线`_`、和数字组成,且第一个字符必须是字母。 + +*下划线`_`是一个特殊的标识符,称为空白标识符* + +标识符的命名需要遵守以下规则: + +- 由 26 个英文字母、0~9、`_`组成; +- 不能以数字开头,例如 `var 1num int `是错误的; +- Go语言中严格区分大小写; +- 标识符不能包含空格; +- 不能以系统保留关键字作为标识符,比如 break,if 等等。 + +命名标识符时还需要注意以下几点: + +- 标识符的命名要尽量采取简短且有意义; +- 不能和标准库中的包名重复; +- 为变量、函数、常量命名时采用驼峰命名法,例如 stuName、getVal; + +在Go语言中还存在着一些特殊的标识符,叫做预定义标识符,如下表所示: + +![img.png](标识符.png) + +## 运算符优先级 + +![img.png](运算符.png) + +_**优先级值越大,表示优先级越高。**_ \ No newline at end of file diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/8.\345\255\227\347\254\246\344\270\262\344\270\216\345\205\266\344\273\226\347\261\273\345\236\213\350\275\254\346\215\242.md" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/8.\345\255\227\347\254\246\344\270\262\344\270\216\345\205\266\344\273\226\347\261\273\345\236\213\350\275\254\346\215\242.md" new file mode 100644 index 0000000000000000000000000000000000000000..cc17b8332cc9f3f4b1e8355f07db304104dc1ab4 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/8.\345\255\227\347\254\246\344\270\262\344\270\216\345\205\266\344\273\226\347\261\273\345\236\213\350\275\254\346\215\242.md" @@ -0,0 +1,36 @@ +### 1.整数 与 字符串 + + // 字符串与其他类型的转换 + // str 转 int + newStr1 := "1" + intValue, _ := strconv.Atoi(newStr1) + fmt.Printf("%T,%d\n", intValue, intValue) // int,1 + + // int 转 str + intValue2 := 1 + strValue := strconv.Itoa(intValue2) + fmt.Printf("%T, %s\n", strValue, strValue) + +### 2.浮点数 与字符串 + + // str 转 float + string3 := "3.1415926" + f,_ := strconv.ParseFloat(string3, 32) + fmt.Printf("%T, %f\n", f, f) // float64, 3.141593 + + //float 转 string + floatValue := 3.1415926 + //4个参数,1:要转换的浮点数 2. 格式标记(b、e、E、f、g、G) + //3. 精度 4. 指定浮点类型(32:float32、64:float64) + // 格式标记: + // ‘b’ (-ddddp±ddd,二进制指数) + // ‘e’ (-d.dddde±dd,十进制指数) + // ‘E’ (-d.ddddE±dd,十进制指数) + // ‘f’ (-ddd.dddd,没有指数) + // ‘g’ (‘e’:大指数,‘f’:其它情况) + // ‘G’ (‘E’:大指数,‘f’:其它情况) + + // 如果格式标记为 ‘e’,‘E’和’f’,则 prec 表示小数点后的数字位数 + // 如果格式标记为 ‘g’,‘G’,则 prec 表示总的数字位数(整数部分+小数部分) + formatFloat := strconv.FormatFloat(floatValue, 'f', 2, 64) + fmt.Printf("%T,%s",formatFloat,formatFloat) \ No newline at end of file diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/9.map.md" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/9.map.md" new file mode 100644 index 0000000000000000000000000000000000000000..4c53015ef3dc51ac5e9690ebe77ea02d94800904 --- /dev/null +++ "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/9.map.md" @@ -0,0 +1,132 @@ +## 概述 +map 是一种无序的`键值对`的集合;通过 key 来快速检索数据,key 类似于索引, +指向数据的值; + +map 是引用类型,可以使用如下方式声明: + + //[keytype] 和 valuetype 之间允许有空格。 + var mapname map[keytype]valuetype + +在声明的时候不需要知道 map 的长度,因为 map 是可以动态增长的, +未初始化的 map 的值是 nil,使用函数 len() 可以获取 map 中 键值对的数目。 + +### 例: + package main + + import "fmt" + + func main() { + var mapLit map[string]int + var mapAssigned map[string]int + mapLit = map[string]int{"one": 1, "two": 2} + + mapAssigned = mapLit + //mapAssigned 是 mapList 的引用,对 mapAssigned 的修改也会影响到 mapList 的值。 + mapAssigned["two"] = 3 + + fmt.Printf("Map literal at \"one\" is: %d\n", mapLit["one"]) + fmt.Printf("Map assigned at \"two\" is: %d\n", mapLit["two"]) + fmt.Printf("Map literal at \"ten\" is: %d\n", mapLit["ten"]) + } + +另外一种构建方式: + + make(map[keytype]valuetype, cap) + + map2 := make(map[string]int, 100) + +## 1. 遍历map + +map 的遍历过程使用 for range 循环完成: + + scene := make(map[string]int) + scene["cat"] = 66 + scene["dog"] = 4 + scene["pig"] = 960 + for k, v := range scene { + fmt.Println(k, v) + } + +## 2. 删除 + +使用 delete() 内建函数从 map 中删除一组键值对,delete() 函数的格式: + + delete(map, 键) + + scene := make(map[string]int) + // 准备map数据 + scene["cat"] = 66 + scene["dog"] = 4 + scene["pig"] = 960 + delete(scene, "dog") + + for k, v := range scene { + fmt.Println(k, v) + } + +**Go语言中并没有为 map 提供任何清空所有元素的函数、方法,清空 map 的唯一办法就是重新 make 一个新的 map** + +## 3. 线程安全的map + +并发情况下读写 map 时会出现问题,代码如下: + + // 创建一个int到int的映射 + m := make(map[int]int) + // 开启一段并发代码 + go func() { + // 不停地对map进行写入 + for { + m[1] = 1 + } + }() + // 开启一段并发代码 + go func() { + // 不停地对map进行读取 + for { + _ = m[1] + } + }() + // 无限循环, 让并发程序在后台执行 + for { + } + +运行代码会报错:`fatal error: concurrent map read and map write` + +Go语言在 1.9 版本中提供了一种效率较高的并发安全的 `sync.Map`,sync.Map 和 map 不同,不是以语言原生形态提供,而是在 sync 包下的特殊结构。 + +sync.Map 有以下特性: + +- 无须初始化,直接声明即可。 +- sync.Map 不能使用 map 的方式进行取值和设置等操作,而是使用 sync.Map 的方法进行调用,Store 表示存储,Load 表示获取,Delete 表示删除。 +- 使用 Range 配合一个回调函数进行遍历操作,通过回调函数返回内部遍历出来的值,Range 参数中回调函数的返回值在需要继续迭代遍历时,返回 true,终止迭代遍历时,返回 false。 + + + package main + + import ( + "fmt" + "sync" + ) + + func main() { + //sync.Map 不能使用 make 创建 + var scene sync.Map + + // 将键值对保存到sync.Map + //sync.Map 将键和值以 interface{} 类型进行保存。 + scene.Store("greece", 97) + scene.Store("london", 100) + scene.Store("egypt", 200) + + // 从sync.Map中根据键取值 + fmt.Println(scene.Load("london")) + // 根据键删除对应的键值对 + scene.Delete("london") + + // 遍历所有sync.Map中的键值对 + //遍历需要提供一个匿名函数,参数为 k、v,类型为 interface{},每次 Range() 在遍历一个元素时,都会调用这个匿名函数把结果返回。 + scene.Range(func(k, v interface{}) bool { + fmt.Println("iterate:", k, v) + return true + }) + } \ No newline at end of file diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/GOPATH.png" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/GOPATH.png" new file mode 100644 index 0000000000000000000000000000000000000000..8f34e1a4f4bba1b0237ce52f4a8abc653b7aab3e Binary files /dev/null and "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/GOPATH.png" differ diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/GOPROXY.png" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/GOPROXY.png" new file mode 100644 index 0000000000000000000000000000000000000000..772d76b8bb49b060897378a7dd1ca6b4950b3630 Binary files /dev/null and "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/GOPROXY.png" differ diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/PATH.png" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/PATH.png" new file mode 100644 index 0000000000000000000000000000000000000000..c27658407a0074b4ba318144f2aacc752b7b6b42 Binary files /dev/null and "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/PATH.png" differ diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/goroot.png" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/goroot.png" new file mode 100644 index 0000000000000000000000000000000000000000..3dc1e05efd7e263205b92169cf529e99dca4e616 Binary files /dev/null and "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/goroot.png" differ diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/mod.png" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/mod.png" new file mode 100644 index 0000000000000000000000000000000000000000..68c353e48611658d49be8b3a31198edf576c78b6 Binary files /dev/null and "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/mod.png" differ diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/mod_2.png" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/mod_2.png" new file mode 100644 index 0000000000000000000000000000000000000000..fa6bac11fd6278e64bcaad4fac403d1313006220 Binary files /dev/null and "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/mod_2.png" differ diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/\345\205\263\351\224\256\345\255\227.png" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/\345\205\263\351\224\256\345\255\227.png" new file mode 100644 index 0000000000000000000000000000000000000000..947a85bbc4197a4eb01b1618eddc230c241ab658 Binary files /dev/null and "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/\345\205\263\351\224\256\345\255\227.png" differ diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/\346\211\247\350\241\214.png" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/\346\211\247\350\241\214.png" new file mode 100644 index 0000000000000000000000000000000000000000..53dc3475d1ae2267d0eff45394cc84c6f39d32da Binary files /dev/null and "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/\346\211\247\350\241\214.png" differ diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/\346\240\207\350\257\206\347\254\246.png" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/\346\240\207\350\257\206\347\254\246.png" new file mode 100644 index 0000000000000000000000000000000000000000..294ddee15affd630ad72ffebfd20d459e470e434 Binary files /dev/null and "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/\346\240\207\350\257\206\347\254\246.png" differ diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/\350\277\220\347\256\227\347\254\246.png" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/\350\277\220\347\256\227\347\254\246.png" new file mode 100644 index 0000000000000000000000000000000000000000..b25cea0ab52a73a11ecd886902f652b7d6d7cda7 Binary files /dev/null and "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/\350\277\220\347\256\227\347\254\246.png" differ diff --git "a/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/\351\205\215\347\275\256.png" "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/\351\205\215\347\275\256.png" new file mode 100644 index 0000000000000000000000000000000000000000..fa5871519131ddcf579bcba24ab14bc57851bf1d Binary files /dev/null and "b/go_base/\345\237\272\347\241\200\350\257\255\346\263\225/notes/\351\205\215\347\275\256.png" differ