ToB企服应用市场:ToB评测及商务社交产业平台

标题: Go学习笔记3 [打印本页]

作者: 傲渊山岳    时间: 2023-9-8 01:59
标题: Go学习笔记3
九、错误处理

1.defer+recover机制处理异常错误

展示错误:
发现:程序中出现错误/恐慌以后,程序被中断,无法继续执行。
错误处理/捕获机制:
内置函数recover:
2.自定义错误

需要调用errors包下的New函数:函数返回error类型
3.panic

有一种情况:程序出现错误以后,后续代码就没有必要执行,想让程序中断,退出程序:
借助:builtin包下内置函数:panic
十、数组

1.使用

数组定义格式:
var 数组名 [数组大小]数据类型
例如:
  1. var scores [5]int
复制代码
  1. package main
  2. import "fmt"
  3. func main(){
  4.         //实现的功能:给出五个学生的成绩,求出成绩的总和,平均数:
  5.         //给出五个学生的成绩:--->数组存储:
  6.         //定义一个数组:
  7.         var scores [5]int
  8.         //将成绩存入数组:
  9.         scores[0] = 95
  10.         scores[1] = 91
  11.         scores[2] = 39
  12.         scores[3] = 60
  13.         scores[4] = 21
  14.         //求和:
  15.         //定义一个变量专门接收成绩的和:
  16.         sum := 0
  17.         for i := 0;i < len(scores);i++ {//i: 0,1,2,3,4
  18.                 sum += scores[i]
  19.         }
  20.         //平均数:
  21.         avg := sum / len(scores)
  22.         //输出
  23.         fmt.Printf("成绩的总和为:%v,成绩的平均数为:%v",sum,avg)
  24. }
复制代码
2.内存分析

赋值内存(数组是值类型,在栈中开辟内存)
3.数组的遍历

【1】普通for循环
【2】键值循环
(键值循环) for range结构是Go语言特有的一种的迭代结构,在许多情况下都非常有用,for range 可以遍历数组、切片、字符串、map 及通道,for range 语法上类似于其它语言中的 foreach 语句,一般形式为:
  1. for key, val := range coll {
  2.     ...
  3. }
复制代码
注意:
(1)coll就是你要的数组
(2)每次遍历得到的索引用key接收,每次遍历得到的索引位置上的值用val
(3)key、value的名字随便起名  k、v   key、value
(4)key、value属于在这个循环中的局部变量
(5)你想忽略某个值:用_就可以了:
  1. package main
  2. import "fmt"
  3. func main(){
  4.         //实现的功能:给出五个学生的成绩,求出成绩的总和,平均数:
  5.         //给出五个学生的成绩:--->数组存储:
  6.         //定义一个数组:
  7.         var scores [5]int
  8.         //将成绩存入数组:(循环 + 终端输入)
  9.         for i := 0; i < len(scores);i++ {//i:数组的下标
  10.                 fmt.Printf("请录入第个%d学生的成绩",i + 1)
  11.                 fmt.Scanln(&scores[i])
  12.         }
  13.         //展示一下班级的每个学生的成绩:(数组进行遍历)
  14.         //方式1:普通for循环:
  15.         for i := 0; i < len(scores);i++ {
  16.                 fmt.Printf("第%d个学生的成绩为:%d\n",i+1,scores[i])
  17.         }
  18.         fmt.Println("-------------------------------")
  19.         //方式2:for-range循环
  20.         for key,value := range scores {
  21.                 fmt.Printf("第%d个学生的成绩为:%d\n",key + 1,value)
  22.         }
  23. }
复制代码
结果:
4.数组的初始化操作
  1. package main
  2. import "fmt"
  3. func main(){
  4.         //第一种:
  5.         var arr1 [3]int = [3]int{3,6,9}
  6.         fmt.Println(arr1)
  7.         //第二种:
  8.         var arr2 = [3]int{1,4,7}
  9.         fmt.Println(arr2)
  10.         //第三种:
  11.         var arr3 = [...]int{4,5,6,7}
  12.         fmt.Println(arr3)
  13.         //第四种:
  14.         var arr4 = [...]int{2:66,0:33,1:99,3:88}
  15.         fmt.Println(arr4)
  16. }
复制代码
5.注意事项

【1】长度属于类型的一部分 :
【2】Go中数组属值类型,在默认情况下是值传递,因此会进行值拷贝。
【3】如想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)。
6.二维数组

二维数组有初始值,
  初始化:
  遍历
  1. package main
  2. import "fmt"
  3. func main(){
  4.         //定义二维数组:
  5.         var arr [3][3]int = [3][3]int{{1,4,7},{2,5,8},{3,6,9}}
  6.         fmt.Println(arr)
  7.         fmt.Println("------------------------")
  8.         //方式1:普通for循环:
  9.         for i := 0;i < len(arr);i++{
  10.                 for j := 0;j < len(arr[i]);j++ {
  11.                         fmt.Print(arr[i][j],"\t")
  12.                 }
  13.                 fmt.Println()
  14.         }
  15.         fmt.Println("------------------------")
  16.         //方式2:for range循环:
  17.         for key,value := range arr {
  18.                 for k,v := range value {
  19.                         fmt.Printf("arr[%v][%v]=%v\t",key,k,v)
  20.                 }
  21.                 fmt.Println()
  22.         }
  23. }
复制代码
十一、切片

【1】切片(slice)是golang中一种特有的数据类型
【2】数组有特定的用处,但是却有一些呆板(数组长度固定不可变),所以在 Go 语言的代码里并不是特别常见。相对的切片却是随处可见的,切片是一种建立在数组类型之上的抽象,它构建在数组之上并且提供更强大的能力和便捷。
【3】切片(slice)是对数组一个连续片段的引用,所以切片是一个引用类型。这个片段可以是整个数组,或者是由起始和终止索引标识的一些项的子集。需要注意的是,终止索引标识的项不包括在切片内。切片提供了一个相关数组的动态窗口。
1.语法
  1. var 切片名 []类型 = 数组的一个片段引用
复制代码
2.内存分析

切片有3个字段的数据结构:一个是指向底层数组的指针,一个是切片的长度,一个是切片的容量。
3.定义

【1】方式1:定义一个切片,然后让切片去引用一个已经创建好的数组。
【2】方式2:通过make内置函数来创建切片。基本语法: var切片名[type = make([], len,[cap])
make底层创建一个数组,对外不可见,所以不可以直接操作这个数组,要通过slice去间接的访问各个元素,不可以直接对数组进行维护/操作
【3】方式3:定一个切片,直接就指定具体数组,使用原理类似make的方式。

4.遍历

【1】方式1:for循环常规方式遍历
【2】方式2:for-range 结构遍历切片
  1. package main
  2. import "fmt"
  3. func main(){
  4.         //定义切片:
  5.         slice := make([]int,4,20)
  6.         slice[0] = 66
  7.         slice[1] = 88
  8.         slice[2] = 99
  9.         slice[3] = 100
  10.         //方式1:普通for循环
  11.         for i := 0;i < len(slice);i++ {
  12.                 fmt.Printf("slice[%v] = %v \t" ,i,slice[i])
  13.         }
  14.         fmt.Println("\n------------------------------")
  15.         //方式2:for-range循环:
  16.         for i,v := range slice {
  17.                 fmt.Printf("下标:%v ,元素:%v\n" ,i,v)
  18.         }
  19. }
复制代码
5.注意事项

【1】切片定义后不可以直接使用,需要让其引用到一个数组,或者make一个空间供切片来使用
【2】切片使用不能越界。
【3】简写方式:
【4】切片可以继续切片

【5】切片可以动态增长
  1. package main
  2. import "fmt"
  3. func main(){
  4.         //定义数组:
  5.         var intarr [6]int = [6]int{1,4,7,3,6,9}
  6.         //定义切片:
  7.         var slice []int = intarr[1:4] //4,7,3
  8.         fmt.Println(len(slice))
  9.         slice2 := append(slice,88,50)
  10.         fmt.Println(slice2) //[4 7 3 88 50]
  11.         fmt.Println(slice)
  12.         //底层原理:
  13.         //1.底层追加元素的时候对数组进行扩容,老数组扩容为新数组:
  14.         //2.创建一个新数组,将老数组中的4,7,3复制到新数组中,在新数组中追加88,50
  15.         //3.slice2 底层数组的指向 指向的是新数组
  16.         //4.往往我们在使用追加的时候其实想要做的效果给slice追加:
  17.         slice = append(slice,88,50)
  18.         fmt.Println(slice)
  19.         //5.底层的新数组 不能直接维护,需要通过切片间接维护操作。
  20. }
复制代码
可以通过append函数将切片追加给切片:

【6】切片的拷贝:
  1. package main
  2. import "fmt"
  3. func main(){
  4.         //定义切片:
  5.         var a []int = []int{1,4,7,3,6,9}
  6.         //再定义一个切片:
  7.         var b []int = make([]int,10)
  8.         //拷贝:
  9.         copy(b,a) //将a中对应数组中元素内容复制到b中对应的数组中
  10.         fmt.Println(b)
  11. }
复制代码
十二、映射

1.map的引入

【1】映射(map), Go语言中内置的一种类型,它将键值对相关联,我们可以通过键 key来获取对应的值 value。 类似其它语言的集合

【2】基本语法
  1. var map变量名 map[keytype]valuetype
复制代码
key、value的类型:bool、数字、string、指针、channel 、还可以是只包含前面几个类型的接口、结构体、数组
key通常为int 、string类型,value通常为数字(整数、浮点数)、string、map、结构体
key:slice、map、function不可以
【3】代码:
map的特点:
(1)map集合在使用前一定要make
(2)map的key-value是无序的
(3)key是不可以重复的,如果遇到重复,后一个value会替换前一个value
(4)value可以重复的
  1. package main
  2. import "fmt"
  3. func main(){
  4.         //定义map变量:
  5.         var a map[int]string
  6.         //只声明map内存是没有分配空间
  7.         //必须通过make函数进行初始化,才会分配空间:
  8.         a = make(map[int]string,10) //map可以存放10个键值对
  9.         //将键值对存入map中:
  10.         a[20095452] = "张三"
  11.         a[20095387] = "李四"
  12.         a[20097291] = "王五"
  13.         a[20095387] = "朱六"
  14.         a[20096699] = "张三"
  15.         //输出集合
  16.         fmt.Println(a)
  17. }
复制代码
2.创建
  1. package main
  2. import "fmt"
  3. func main(){
  4.         //方式1:
  5.         //定义map变量:
  6.         var a map[int]string
  7.         //只声明map内存是没有分配空间
  8.         //必须通过make函数进行初始化,才会分配空间:
  9.         a = make(map[int]string,10) //map可以存放10个键值对
  10.         //将键值对存入map中:
  11.         a[20095452] = "张三"
  12.         a[20095387] = "李四"
  13.         //输出集合
  14.         fmt.Println(a)
  15.         //方式2:
  16.         b := make(map[int]string)
  17.         b[20095452] = "张三"
  18.         b[20095387] = "李四"
  19.         fmt.Println(b)
  20.         //方式3:
  21.         c := map[int]string{
  22.                 20095452 : "张三",
  23.                 20098765 : "李四",
  24.         }
  25.         c[20095387] = "王五"
  26.         fmt.Println(c)
  27. }
复制代码
3.操作

1】增加和更新操作:
map["key"]= value  ——》 如果key还没有,就是增加,如果key存在就是修改。
【2】删除操作:
delete(map,"key") , delete是一个内置函数,如果key存在,就删除该key-value,如果k的y不存在,不操作,但是也不会报错

【3】清空操作:
(1)如果我们要删除map的所有key ,没有一个专门的方法一次删除,可以遍历一下key,逐个删除
(2)或者map = make(...),make一个新的,让原来的成为垃圾,被gc回收
【4】查找操作:
value ,bool = map[key]
value为返回的value,bool为是否返回 ,要么true 要么false
  1. package main
  2. import "fmt"
  3. func main(){
  4.         //定义map
  5.         b := make(map[int]string)
  6.         //增加:
  7.         b[20095452] = "张三"
  8.         b[20095387] = "李四"
  9.         //修改:
  10.         b[20095452] = "王五"
  11.         //删除:
  12.         delete(b,20095387)
  13.         delete(b,20089546)
  14.         fmt.Println(b)
  15.         //查找:
  16.         value,flag := b[200]
  17.         fmt.Println(value)
  18.         fmt.Println(flag)
  19. }
复制代码
【5】获取长度:len函数
【6】遍历:for-range
  1. package main
  2. import "fmt"
  3. func main(){
  4.         //定义map
  5.         b := make(map[int]string)
  6.         //增加:
  7.         b[20095452] = "张三"
  8.         b[20095387] = "李四"
  9.         b[20098833] = "王五"
  10.         //获取长度:
  11.         fmt.Println(len(b))
  12.         //遍历:
  13.         for k,v := range b {
  14.                 fmt.Printf("key为:%v value为%v \t",k,v)
  15.         }
  16.         fmt.Println("---------------------------")
  17.         //加深难度:
  18.         a := make(map[string]map[int]string)
  19.         //赋值:
  20.         a["班级1"] = make(map[int]string,3)
  21.         a["班级1"][20096677] = "露露"
  22.         a["班级1"][20098833] = "丽丽"
  23.         a["班级1"][20097722] = "菲菲"
  24.         a["班级2"] = make(map[int]string,3)
  25.         a["班级2"][20089911] = "小明"
  26.         a["班级2"][20085533] = "小龙"
  27.         a["班级2"][20087244] = "小飞"
  28.         for k1,v1:= range a {
  29.                 fmt.Println(k1)
  30.                 for k2,v2:= range v1{
  31.                         fmt.Printf("学生学号为:%v 学生姓名为%v \t",k2,v2)
  32.                 }
  33.                 fmt.Println()
  34.         }
  35. }
复制代码
十三、对象

1.对象的引入

【1】Golang语言面向对象编程说明:
(1)Golang也支持面向对象编程(OOP),但是和传统的面向对象编程有区别,并不是纯粹的面向对象语言。所以我们说Golang支持面向对象编程特性是比较准确的。
(2)Golang没有类(class),Go语言的结构体(struct)和其它编程语言的类(class)有同等的地位,你可以理解Gelang是基于struct来实现OOP特性的。
(3)Golang面向对象编程非常简洁,去掉了传统OOP语言的方法重载、构造函数和析构函数、隐藏的this指针等等
(4)Golang仍然有面向对象编程的继承,封装和多态的特性,只是实现的方式和其它OOP语言不一样,比如继承:Golang没有extends 关键字,继承是通过匿名字段来实现。
【2】结构体的引入:
具体的对象:
一位老师:郜宇博老师: 姓名:郜宇博   年龄:22岁   性别 :男 ......
可以使用变量来处理:
  1. package main
  2. import "fmt"
  3. func main(){
  4.         //郜宇博老师: 姓名:郜宇博   年龄:22岁   性别 :男 ......
  5.         var name string = "郜宇博"
  6.         var age int = 22
  7.         var sex string = "男"
  8.         //马士兵老师:
  9.         var name2 string = "马士兵"
  10.         var age2 int = 45
  11.         var sex2 string = "男"
  12.       
  13. }
复制代码
缺点:
(1)不利于数据的管理、维护
(2)老师的很多属性属于一个对象,用变量管理太分散了
2.结构体

代码:
  1. package main
  2. import "fmt"
  3. //定义老师结构体,将老师中的各个属性  统一放入结构体中管理:
  4. type Teacher struct{
  5.         //变量名字大写外界可以访问这个属性
  6.         Name string
  7.         Age int
  8.         School string
  9. }
  10. func main(){
  11.         //创建老师结构体的实例、对象、变量:
  12.         var t1 Teacher // var a int
  13.         fmt.Println(t1) //在未赋值时默认值:{ 0 }
  14.         t1.Name = "马士兵"
  15.         t1.Age = 45
  16.         t1.School = "清华大学"
  17.         fmt.Println(t1)
  18.         fmt.Println(t1.Age + 10)
  19. }
复制代码
3.结构体的创建

1.直接创建

2.附带初始值

  3.结构体指针创建

  4.结构体之间转换

【1】结构体是用户单独定义的类型,和其它类型进行转换时需要有完全相同的字段(名字、个数和类型)
  1. package main
  2. import "fmt"
  3. type Student struct {
  4.         Age int
  5. }
  6. type Person struct {
  7.         Age int
  8. }
  9. func main(){
  10.         var s Student = Student{10}
  11.         var p Person = Person{10}
  12.         s = Student(p)
  13.         fmt.Println(s)
  14.         fmt.Println(p)
  15. }
复制代码
【2】结构体进行type重新定义(相当于取别名),Golang认为是新的数据类型,但是相互间可以强转
  1. package main
  2. import "fmt"
  3. type Student struct {
  4.         Age int
  5. }
  6. type Stu Student
  7. func main(){
  8.         var s1 Student = Student{19}
  9.         var s2 Stu = Stu{19}
  10.         s1 = Student(s2)
  11.         fmt.Println(s1)
  12.         fmt.Println(s2)
  13. }
复制代码
5.方法的引入

【1】方法是作用在指定的数据类型上、和指定的数据类型绑定,因此自定义类型,都可以有方法,而不仅仅是struct
【2】方法的声明和调用格式:
声明:
  1. type A struct {
  2.                 Num int
  3. }
  4. func (a A) test() {
  5.                 fmt.Println(a.Num)
  6. }
复制代码
调用:
  1. var a A
  2. a.test()
复制代码
(1)func (a A) test()相当于A结构体有一个方法叫test
(2)(a A)体现方法test和结构体A绑定关系
(3)代码层面:
  注意:
(1)test方法中参数名字随意起
(2)结构体Person和test方法绑定,调用test方法必须靠指定的类型:Person
(3)如果其他类型变量调用test方法一定会报错。
(4)结构体对象传入test方法中,值传递,和函数参数传递一致。
6.方法的注意事项

(1)结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式

(2)如程序员希望在方法中,改变结构体变量的值,可以通过结构体指针的方式来处理
我们写程序的时候,可以直接简化:
底层编译器做了优化,底层会自动帮我们加上 &  *
(3)Golang中的方法作用在指定的数据类型上的,和指定的数据类型绑定,因此自定义类型,都可以有方法,而不仅仅是struct,比如int , float32等都可以有方法
  1. package main
  2. import "fmt"
  3. type integer int
  4. func (i integer) print(){
  5.         i = 30
  6.         fmt.Println("i = ",i)
  7. }
  8. func (i *integer) change(){
  9.         *i = 30
  10.         fmt.Println("i = ",*i)
  11. }
  12. func main(){
  13.         var i integer = 20
  14.         i.print()
  15.         i.change()
  16.         fmt.Println(i)
  17. }
复制代码
(4)方法的访问范围控制的规则,和函数一样。方法名首字母小写,只能在本包访问,方法首字母大写,可以在本包和其它包访问。
(5)如果一个类型实现了String()这个方法,那么fmt.Println默认会调用这个变量的String()进行输出
以后定义结构体的话,常定义String()作为输出结构体信息的方法,在fmt.Println会自动调用
  1. package main
  2. import "fmt"
  3. type Student struct{
  4.         Name string
  5.         Age int
  6. }
  7. func (s *Student) String() string{
  8.         str := fmt.Sprintf("Name = %v , Age = %v",s.Name,s.Age)
  9.         return str
  10. }
  11. func main(){
  12.         stu := Student{
  13.                 Name : "丽丽",
  14.                 Age : 20,
  15.         }
  16.         //传入地址,如果绑定了String方法就会自动调用
  17.         fmt.Println(&stu)
  18. }
复制代码
7.方法和函数的区别

【1】绑定指定类型:
方法:需要绑定指定数据类型
函数:不需要绑定数据类型
【2】调用方式不一样:
函数的调用方式:
函数名(实参列表)
方法的调用方式:变量.方法名(实参列表)
  1. package main
  2. import "fmt"
  3. type Student struct{
  4.         Name string
  5. }
  6. //定义方法:
  7. func (s Student) test01(){
  8.         fmt.Println(s.Name)
  9. }
  10. //定义函数:
  11. func method01(s Student){
  12.         fmt.Println(s.Name)
  13. }
  14. func main(){
  15.         //调用函数:
  16.         var s Student = Student{"丽丽"}
  17.         method01(s)
  18.         //方法调用:
  19.         s.test01()
  20. }
复制代码
【3】对于函数来说,参数类型对应是什么就要传入什么。
  1. package main
  2. import "fmt"
  3. type Student struct{
  4.         Name string
  5. }
  6. //定义函数:
  7. func method01(s Student){
  8.         fmt.Println(s.Name)
  9. }
  10. func method02(s *Student){
  11.         fmt.Println((*s).Name)
  12. }
  13. func main(){
  14.         var s Student = Student{"丽丽"}
  15.         method01(s)
  16.         //method01(&s)错误
  17.         method02(&s)
  18.         //method02(s)错误
  19. }
复制代码
【4】对于方法来说,接收者为值类型,可以传入指针类型,接受者为指针类型,可以传入值类型。
  1. package main
  2. import "fmt"
  3. type Student struct{
  4.         Name string
  5. }
  6. //定义方法:
  7. func (s Student) test01(){
  8.         fmt.Println(s.Name)
  9. }
  10. func (s *Student) test02(){
  11.         fmt.Println((*s).Name)
  12. }
  13. func main(){
  14.         var s Student = Student{"丽丽"}
  15.         s.test01()
  16.         (&s).test01()//虽然用指针类型调用,但是传递还是按照值传递的形式
  17.         (&s).test02()
  18.         s.test02()//等价
  19. }
复制代码
8.创建结构体时初始化

【1】方式1:按照顺序赋值操作
缺点:必须按照顺序有局限性
【2】方式2:按照指定类型
【3】方式3:想要返回结构体的指针类型

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4