Go学习笔记3
九、错误处理
1.defer+recover机制处理异常错误
展示错误:
发现:程序中出现错误/恐慌以后,程序被中断,无法继续执行。
错误处理/捕获机制:
内置函数recover:
2.自定义错误
需要调用errors包下的New函数:函数返回error类型
3.panic
有一种情况:程序出现错误以后,后续代码就没有必要执行,想让程序中断,退出程序:
借助:builtin包下内置函数:panic
十、数组
1.使用
数组定义格式:
var 数组名 [数组大小]数据类型
例如:
var scores [5]int
package main
import "fmt"
func main(){
//实现的功能:给出五个学生的成绩,求出成绩的总和,平均数:
//给出五个学生的成绩:--->数组存储:
//定义一个数组:
var scores [5]int
//将成绩存入数组:
scores[0] = 95
scores[1] = 91
scores[2] = 39
scores[3] = 60
scores[4] = 21
//求和:
//定义一个变量专门接收成绩的和:
sum := 0
for i := 0;i < len(scores);i++ {//i: 0,1,2,3,4
sum += scores[i]
}
//平均数:
avg := sum / len(scores)
//输出
fmt.Printf("成绩的总和为:%v,成绩的平均数为:%v",sum,avg)
}
2.内存分析
赋值内存(数组是值类型,在栈中开辟内存)
3.数组的遍历
【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)你想忽略某个值:用_就可以了:
package main
import "fmt"
func main(){
//实现的功能:给出五个学生的成绩,求出成绩的总和,平均数:
//给出五个学生的成绩:--->数组存储:
//定义一个数组:
var scores [5]int
//将成绩存入数组:(循环 + 终端输入)
for i := 0; i < len(scores);i++ {//i:数组的下标
fmt.Printf("请录入第个%d学生的成绩",i + 1)
fmt.Scanln(&scores[i])
}
//展示一下班级的每个学生的成绩:(数组进行遍历)
//方式1:普通for循环:
for i := 0; i < len(scores);i++ {
fmt.Printf("第%d个学生的成绩为:%d\n",i+1,scores[i])
}
fmt.Println("-------------------------------")
//方式2:for-range循环
for key,value := range scores {
fmt.Printf("第%d个学生的成绩为:%d\n",key + 1,value)
}
}
结果:
4.数组的初始化操作
package main
import "fmt"
func main(){
//第一种:
var arr1 [3]int = [3]int{3,6,9}
fmt.Println(arr1)
//第二种:
var arr2 = [3]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】长度属于类型的一部分 :
【2】Go中数组属值类型,在默认情况下是值传递,因此会进行值拷贝。
【3】如想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)。
6.二维数组
二维数组有初始值,
初始化:
遍历
package main
import "fmt"
func main(){
//定义二维数组:
var arr [3][3]int = [3][3]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[i]);j++ {
fmt.Print(arr[i][j],"\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 切片名 []类型 = 数组的一个片段引用
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 结构遍历切片
package main
import "fmt"
func main(){
//定义切片:
slice := make([]int,4,20)
slice[0] = 66
slice[1] = 88
slice[2] = 99
slice[3] = 100
//方式1:普通for循环
for i := 0;i < len(slice);i++ {
fmt.Printf("slice[%v] = %v \t" ,i,slice[i])
}
fmt.Println("\n------------------------------")
//方式2:for-range循环:
for i,v := range slice {
fmt.Printf("下标:%v ,元素:%v\n" ,i,v)
}
}
5.注意事项
【1】切片定义后不可以直接使用,需要让其引用到一个数组,或者make一个空间供切片来使用
【2】切片使用不能越界。
【3】简写方式:
- var slice = arr[0:end] ----》 var slice = arr[:end]
- var slice = arr[start:len(arr)] ----》 var slice = arr[start:]
- var slice = arr[0:len(arr)] ----》 var slice = arr[:]
【4】切片可以继续切片
【5】切片可以动态增长
package main
import "fmt"
func main(){
//定义数组:
var intarr [6]int = [6]int{1,4,7,3,6,9}
//定义切片:
var slice []int = intarr[1:4] //4,7,3
fmt.Println(len(slice))
slice2 := append(slice,88,50)
fmt.Println(slice2) //[4 7 3 88 50]
fmt.Println(slice)
//底层原理:
//1.底层追加元素的时候对数组进行扩容,老数组扩容为新数组:
//2.创建一个新数组,将老数组中的4,7,3复制到新数组中,在新数组中追加88,50
//3.slice2 底层数组的指向 指向的是新数组
//4.往往我们在使用追加的时候其实想要做的效果给slice追加:
slice = append(slice,88,50)
fmt.Println(slice)
//5.底层的新数组 不能直接维护,需要通过切片间接维护操作。
}
可以通过append函数将切片追加给切片:
【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。 类似其它语言的集合
【2】基本语法
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可以重复的
package main
import "fmt"
func main(){
//定义map变量:
var a map[int]string
//只声明map内存是没有分配空间
//必须通过make函数进行初始化,才会分配空间:
a = make(map[int]string,10) //map可以存放10个键值对
//将键值对存入map中:
a[20095452] = "张三"
a[20095387] = "李四"
a[20097291] = "王五"
a[20095387] = "朱六"
a[20096699] = "张三"
//输出集合
fmt.Println(a)
}
2.创建
package main
import "fmt"
func main(){
//方式1:
//定义map变量:
var a map[int]string
//只声明map内存是没有分配空间
//必须通过make函数进行初始化,才会分配空间:
a = make(map[int]string,10) //map可以存放10个键值对
//将键值对存入map中:
a[20095452] = "张三"
a[20095387] = "李四"
//输出集合
fmt.Println(a)
//方式2:
b := make(map[int]string)
b[20095452] = "张三"
b[20095387] = "李四"
fmt.Println(b)
//方式3:
c := map[int]string{
20095452 : "张三",
20098765 : "李四",
}
c[20095387] = "王五"
fmt.Println(c)
}
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
package main
import "fmt"
func main(){
//定义map
b := make(map[int]string)
//增加:
b[20095452] = "张三"
b[20095387] = "李四"
//修改:
b[20095452] = "王五"
//删除:
delete(b,20095387)
delete(b,20089546)
fmt.Println(b)
//查找:
value,flag := b[200]
fmt.Println(value)
fmt.Println(flag)
}
【5】获取长度:len函数
【6】遍历:for-range
package main
import "fmt"
func main(){
//定义map
b := make(map[int]string)
//增加:
b[20095452] = "张三"
b[20095387] = "李四"
b[20098833] = "王五"
//获取长度:
fmt.Println(len(b))
//遍历:
for k,v := range b {
fmt.Printf("key为:%v value为%v \t",k,v)
}
fmt.Println("---------------------------")
//加深难度:
a := make(map[string]map[int]string)
//赋值:
a["班级1"] = make(map[int]string,3)
a["班级1"][20096677] = "露露"
a["班级1"][20098833] = "丽丽"
a["班级1"][20097722] = "菲菲"
a["班级2"] = make(map[int]string,3)
a["班级2"][20089911] = "小明"
a["班级2"][20085533] = "小龙"
a["班级2"][20087244] = "小飞"
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.直接创建
2.附带初始值
3.结构体指针创建
4.结构体之间转换
【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)代码层面:
注意:
(1)test方法中参数名字随意起
(2)结构体Person和test方法绑定,调用test方法必须靠指定的类型:Person
(3)如果其他类型变量调用test方法一定会报错。
(4)结构体对象传入test方法中,值传递,和函数参数传递一致。
6.方法的注意事项
(1)结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式
(2)如程序员希望在方法中,改变结构体变量的值,可以通过结构体指针的方式来处理
我们写程序的时候,可以直接简化:
底层编译器做了优化,底层会自动帮我们加上 & *
(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:想要返回结构体的指针类型
Go学习笔记3的更多相关文章
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
- 2014年暑假c#学习笔记目录
2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- seaJs学习笔记2 – seaJs组建库的使用
原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...
- CSS学习笔记
CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...
- HTML学习笔记
HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...
- DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记
今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...
- ucos实时操作系统学习笔记——任务间通信(消息)
ucos另一种任务间通信的机制是消息(mbox),个人感觉是它是queue中只有一个信息的特殊情况,从代码中可以很清楚的看到,因为之前有关于queue的学习笔记,所以一并讲一下mbox.为什么有了qu ...
随机推荐
- Typo in static class property declarationeslint
eslint 检测提示 Typo in static class property declarationeslint 找了半天原来是propTypes 写成了PropTypes (就是一个首字母大写 ...
- web自动化09-frame切换、多窗口切换
frame切换 1.html代码: <frameset cols="25%,50%,25%"> <frame src="a.htm"> ...
- C++温故补缺(二十一):杂项补充2
杂记2 explicit 在 C++ 中,explicit 是一个关键字,用于修饰类的构造函数,其作用是禁止编译器将一个参数构造函数用于隐式类型转换.具体来说,当一个构造函数被 explicit 修饰 ...
- C/CPP在命令行中生成DLL文件
简单的写一个C调用DLL(动态链接库)的例子. 创建3个.c文件备用 test.c 1 #include <stdio.h> 2 3 //这里声明,表示来自dll文件. 4 extern ...
- 一文搞懂V8引擎的垃圾回收机制
前言 我们平时在写代码的过程中,好像很少需要自己手动进行垃圾回收,那么V8是如何来减少内存占用,从而避免内存溢出而导致程序崩溃的情况的.为了更高效地回收垃圾,V8引入了两个垃圾回收器,它们分别针对不同 ...
- Rust的类型系统
Rust的类型系统 类型于20世纪50年代被FORTRAN语言引入,其相关的理论和应用已经发展得非常成熟.现在,类型系统已经成为了各大编程语言的核心基础. 通用基础 所谓类型,就是对表示信息的值进行的 ...
- 软件开发架构及OSI七层协议
软件开发架构 规定了程序的请求逻辑.功能分块 1.C/S架构 Client:客户端 Server: 服务端 """ 我们使用计算机下载下俩的一个个app本质是各大互联网公 ...
- R数据分析:解决科研中的“可重复危机”,理解Rmarkdown
不知道刚接触科研的大伙儿有没有这么一个感觉,别人的研究很大可能你重复不出来,尤其是社科实证研究,到现在我都还觉得所谓的实证是个很玄乎的东西: 如果是刚开始做数据分析,很多时候你会发现自己的分析结果过几 ...
- 【神经网络】基于GAN的生成对抗网络
目录 [神经网络]基于GAN的生成对抗网络 随着深度学习的快速发展,神经网络逐渐成为人工智能领域的热点话题.神经网络是一种模仿人脑计算方式的算法,其通过大量数据和复杂的计算模型,能够实现复杂的任务和预 ...
- 白嫖一个WebAPI限流解决方案
什么是API限流: API 限流是限制用户在一定时间内 API 请求数量的过程.应用程序编程接口 (API) 充当用户和软件应用程序之间的网关.例如,当用户单击社交媒体上的发布按钮时,点击该按钮会触发 ...