傲渊山岳 发表于 2023-9-8 01:59:10

Go学习笔记3

九、错误处理

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

展示错误:
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233734931-697607634.png 发现:程序中出现错误/恐慌以后,程序被中断,无法继续执行。
错误处理/捕获机制:
内置函数recover:
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233734910-2022130242.png https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735208-822894550.png 2.自定义错误

需要调用errors包下的New函数:函数返回error类型
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735054-337967038.png https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735592-1130484412.png 3.panic

有一种情况:程序出现错误以后,后续代码就没有必要执行,想让程序中断,退出程序:
借助:builtin包下内置函数:panic
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233734950-1781834691.png https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735595-343529575.png十、数组

1.使用

数组定义格式:
var 数组名 [数组大小]数据类型
例如:
var scores intpackage main
import "fmt"
func main(){
      //实现的功能:给出五个学生的成绩,求出成绩的总和,平均数:
      //给出五个学生的成绩:--->数组存储:
      //定义一个数组:
      var scores int
      //将成绩存入数组:
      scores = 95
      scores = 91
      scores = 39
      scores = 60
      scores = 21
      //求和:
      //定义一个变量专门接收成绩的和:
      sum := 0
      for i := 0;i < len(scores);i++ {//i: 0,1,2,3,4
                sum += scores
      }
      //平均数:
      avg := sum / len(scores)
      //输出
      fmt.Printf("成绩的总和为:%v,成绩的平均数为:%v",sum,avg)
}2.内存分析

https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735370-593882382.png赋值内存(数组是值类型,在栈中开辟内存)
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735391-921636106.png3.数组的遍历

【1】普通for循环
【2】键值循环
(键值循环) for range结构是Go语言特有的一种的迭代结构,在许多情况下都非常有用,for range 可以遍历数组、切片、字符串、map 及通道,for range 语法上类似于其它语言中的 foreach 语句,一般形式为:
for key, val := range coll {
    ...
}注意:
(1)coll就是你要的数组
(2)每次遍历得到的索引用key接收,每次遍历得到的索引位置上的值用val
(3)key、value的名字随便起名k、v   key、value
(4)key、value属于在这个循环中的局部变量
(5)你想忽略某个值:用_就可以了:
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735321-2107501213.pngpackage main
import "fmt"
func main(){
      //实现的功能:给出五个学生的成绩,求出成绩的总和,平均数:
      //给出五个学生的成绩:--->数组存储:
      //定义一个数组:
      var scores int
      //将成绩存入数组:(循环 + 终端输入)
      for i := 0; i < len(scores);i++ {//i:数组的下标
                fmt.Printf("请录入第个%d学生的成绩",i + 1)
                fmt.Scanln(&scores)
      }
      //展示一下班级的每个学生的成绩:(数组进行遍历)
      //方式1:普通for循环:
      for i := 0; i < len(scores);i++ {
                fmt.Printf("第%d个学生的成绩为:%d\n",i+1,scores)
      }
      fmt.Println("-------------------------------")
      //方式2:for-range循环
      for key,value := range scores {
                fmt.Printf("第%d个学生的成绩为:%d\n",key + 1,value)
      }
}结果:
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735597-470195411.png 4.数组的初始化操作

package main
import "fmt"
func main(){
      //第一种:
      var arr1 int = int{3,6,9}
      fmt.Println(arr1)
      //第二种:
      var arr2 = int{1,4,7}
      fmt.Println(arr2)
      //第三种:
      var arr3 = [...]int{4,5,6,7}
      fmt.Println(arr3)
      //第四种:
      var arr4 = [...]int{2:66,0:33,1:99,3:88}
      fmt.Println(arr4)
}5.注意事项

【1】长度属于类型的一部分 :
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735415-1673253130.png 【2】Go中数组属值类型,在默认情况下是值传递,因此会进行值拷贝。
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735469-361555717.png【3】如想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)。
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735439-2054368579.png6.二维数组

二维数组有初始值,
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735410-1372057408.png初始化:
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735360-1631857302.png遍历

package main
import "fmt"
func main(){
      //定义二维数组:
      var arr int = int{{1,4,7},{2,5,8},{3,6,9}}
      fmt.Println(arr)
      fmt.Println("------------------------")
      //方式1:普通for循环:
      for i := 0;i < len(arr);i++{
                for j := 0;j < len(arr);j++ {
                        fmt.Print(arr,"\t")
                }
                fmt.Println()
      }
      fmt.Println("------------------------")
      //方式2:for range循环:
      for key,value := range arr {
                for k,v := range value {
                        fmt.Printf("arr[%v][%v]=%v\t",key,k,v)
                }
                fmt.Println()
      }
}十一、切片

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

var 切片名 []类型 = 数组的一个片段引用https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735707-1704396510.png 2.内存分析

切片有3个字段的数据结构:一个是指向底层数组的指针,一个是切片的长度,一个是切片的容量。
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735457-1392663811.png 3.定义

【1】方式1:定义一个切片,然后让切片去引用一个已经创建好的数组。
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735464-776432898.png 【2】方式2:通过make内置函数来创建切片。基本语法: var切片名, len,)
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735595-313733691.png make底层创建一个数组,对外不可见,所以不可以直接操作这个数组,要通过slice去间接的访问各个元素,不可以直接对数组进行维护/操作
【3】方式3:定一个切片,直接就指定具体数组,使用原理类似make的方式。
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735267-767947595.png
4.遍历

【1】方式1:for循环常规方式遍历
【2】方式2:for-range 结构遍历切片
package main
import "fmt"
func main(){
      //定义切片:
      slice := make([]int,4,20)
      slice = 66
      slice = 88
      slice = 99
      slice = 100
      //方式1:普通for循环
      for i := 0;i < len(slice);i++ {
                fmt.Printf("slice[%v] = %v \t" ,i,slice)
      }
      fmt.Println("\n------------------------------")
      //方式2:for-range循环:
      for i,v := range slice {
                fmt.Printf("下标:%v ,元素:%v\n" ,i,v)
      }
}5.注意事项

【1】切片定义后不可以直接使用,需要让其引用到一个数组,或者make一个空间供切片来使用
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735599-1470814385.png 【2】切片使用不能越界。
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735593-1979904088.png【3】简写方式:

[*]var slice = arr----》 var slice = arr[:end]
[*]var slice = arr----》var slice = arr
[*]var slice = arr   ----》 var slice = arr[:]
【4】切片可以继续切片
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735496-1590209930.png
【5】切片可以动态增长
package main
import "fmt"
func main(){
      //定义数组:
      var intarr int = int{1,4,7,3,6,9}
      //定义切片:
      var slice []int = intarr //4,7,3
      fmt.Println(len(slice))
      slice2 := append(slice,88,50)
      fmt.Println(slice2) //
      fmt.Println(slice)
      //底层原理:
      //1.底层追加元素的时候对数组进行扩容,老数组扩容为新数组:
      //2.创建一个新数组,将老数组中的4,7,3复制到新数组中,在新数组中追加88,50
      //3.slice2 底层数组的指向 指向的是新数组
      //4.往往我们在使用追加的时候其实想要做的效果给slice追加:
      slice = append(slice,88,50)
      fmt.Println(slice)
      //5.底层的新数组 不能直接维护,需要通过切片间接维护操作。
}可以通过append函数将切片追加给切片:
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735392-1949510066.png
【6】切片的拷贝:
package main
import "fmt"
func main(){
      //定义切片:
      var a []int = []int{1,4,7,3,6,9}
      //再定义一个切片:
      var b []int = make([]int,10)
      //拷贝:
      copy(b,a) //将a中对应数组中元素内容复制到b中对应的数组中
      fmt.Println(b)
}十二、映射

1.map的引入

【1】映射(map), Go语言中内置的一种类型,它将键值对相关联,我们可以通过键 key来获取对应的值 value。 类似其它语言的集合
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735598-818708310.png
【2】基本语法
var map变量名 mapvaluetypekey、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可以重复的
package main
import "fmt"
func main(){
      //定义map变量:
      var a mapstring
      //只声明map内存是没有分配空间
      //必须通过make函数进行初始化,才会分配空间:
      a = make(mapstring,10) //map可以存放10个键值对
      //将键值对存入map中:
      a = "张三"
      a = "李四"
      a = "王五"
      a = "朱六"
      a = "张三"
      //输出集合
      fmt.Println(a)
}2.创建

package main
import "fmt"
func main(){
      //方式1:
      //定义map变量:
      var a mapstring
      //只声明map内存是没有分配空间
      //必须通过make函数进行初始化,才会分配空间:
      a = make(mapstring,10) //map可以存放10个键值对
      //将键值对存入map中:
      a = "张三"
      a = "李四"
      //输出集合
      fmt.Println(a)
      //方式2:
      b := make(mapstring)
      b = "张三"
      b = "李四"
      fmt.Println(b)
      //方式3:
      c := mapstring{
                20095452 : "张三",
                20098765 : "李四",
      }
      c = "王五"
      fmt.Println(c)
}3.操作

1】增加和更新操作:
map["key"]= value——》 如果key还没有,就是增加,如果key存在就是修改。
【2】删除操作:
delete(map,"key") , delete是一个内置函数,如果key存在,就删除该key-value,如果k的y不存在,不操作,但是也不会报错
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735376-684476778.png
【3】清空操作:
(1)如果我们要删除map的所有key ,没有一个专门的方法一次删除,可以遍历一下key,逐个删除
(2)或者map = make(...),make一个新的,让原来的成为垃圾,被gc回收
【4】查找操作:
value ,bool = map
value为返回的value,bool为是否返回 ,要么true 要么false
package main
import "fmt"
func main(){
      //定义map
      b := make(mapstring)
      //增加:
      b = "张三"
      b = "李四"
      //修改:
      b = "王五"
      //删除:
      delete(b,20095387)
      delete(b,20089546)
      fmt.Println(b)
      //查找:
      value,flag := b
      fmt.Println(value)
      fmt.Println(flag)
}【5】获取长度:len函数
【6】遍历:for-range
package main
import "fmt"
func main(){
      //定义map
      b := make(mapstring)
      //增加:
      b = "张三"
      b = "李四"
      b = "王五"
      //获取长度:
      fmt.Println(len(b))
      //遍历:
      for k,v := range b {
                fmt.Printf("key为:%v value为%v \t",k,v)
      }
      fmt.Println("---------------------------")
      //加深难度:
      a := make(mapmapstring)
      //赋值:
      a["班级1"] = make(mapstring,3)
      a["班级1"] = "露露"
      a["班级1"] = "丽丽"
      a["班级1"] = "菲菲"
      a["班级2"] = make(mapstring,3)
      a["班级2"] = "小明"
      a["班级2"] = "小龙"
      a["班级2"] = "小飞"
      for k1,v1:= range a {
                fmt.Println(k1)
                for k2,v2:= range v1{
                        fmt.Printf("学生学号为:%v 学生姓名为%v \t",k2,v2)
                }
                fmt.Println()
      }
}十三、对象

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岁   性别 :男 ......
可以使用变量来处理:
package main
import "fmt"
func main(){
      //郜宇博老师: 姓名:郜宇博   年龄:22岁   性别 :男 ......
      var name string = "郜宇博"
      var age int = 22
      var sex string = "男"
      //马士兵老师:
      var name2 string = "马士兵"
      var age2 int = 45
      var sex2 string = "男"
      
}缺点:
(1)不利于数据的管理、维护
(2)老师的很多属性属于一个对象,用变量管理太分散了
2.结构体

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

1.直接创建

https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735595-1305916094.png 2.附带初始值

https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735751-337257948.png3.结构体指针创建

https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735584-1055352415.png https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735951-143298109.png4.结构体之间转换

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

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

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

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

【1】方式1:按照顺序赋值操作
缺点:必须按照顺序有局限性
【2】方式2:按照指定类型
【3】方式3:想要返回结构体的指针类型
https://img2023.cnblogs.com/blog/2319323/202309/2319323-20230907233735772-61801027.png
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Go学习笔记3