go基础+视频学习资料

背景

研发开始使用go开发,所以跟上潮流学习一下,之前一边看视频一遍做了笔记,记录一下,作为复习巩固使用

资料

1,整理到了百度云盘上:链接:https://pan.baidu.com/s/1522w8sc_KZ38inS1TtmFig
提取码:q8zj
2,bilibili上感觉讲得很好:https://www.bilibili.com/video/BV1x5411h7Md

笔记

基础
基本数据类型有: 整型、浮点型、布尔型、字符串
复合数据类型有: 数组、切片、结构体、函数、map、通道(channel)、接口等

一,变量及常量:

(1)变量
go语言中的变量被定义后需要使用,没被使用会报错
需要声明关键字var,声明整型但是未赋值石默认是0
相同类型变量声明 var a,b int =10,20
不同类型变量声明

var (
   a int =1
   b float64=2.0
)

推导式变量:
a := 3 —这种情况下a就不需要再定义变量
出现在 := 左侧的变量不应该是已经被声明过,:=定义时必须初始化
多重赋值
a,b,c := 3,4,5.8

(2)常量
声明关键字const

const i int =30
const(
    i int =20
    j folat64=7.89
)

动推导

const(
  i=10
  j=5.67
)

println 打印并换行,常规使用这种打印方式
printf 需要加格式化字符串打印,且需要加 /n 才能 换行

_ 匿名变量 --丢弃数据不处理,配合返回值使用,接受返回值而不使用
a,_ :=2,3 这里_赋值后可以不被使用

(3)iota枚举
iota给常量赋值使用
iota是常量自动生成器,每个一行,自动加1
iota遇到const,重置为0
在一个括号里,可以只写一个iota
如果在同一行,iota值一样
常量定义时,如果穿插使用iota,则看当前iota在第几行,那变量被赋值到的值就是几
定义时,可以结合到表达式里

二,基础类型

(1)bool类型
var a bool 声明变量,没有初始化,零值 为false
布尔类型不接受其他类型的赋值,也不支持自动或强制的类型转换,比如a=bool(1)
自动推导类型
a :=false
b :=(1==2)

(2)整型
自动推导默认是int64类型

(3)浮点类型
浮点类型数据分为单精度float32和双精度float64
自动推导是默认是float64

(4)字符类型 —单引号表示的是字符
go语言中,单引号表示的是字符,双引号表示字符串
字符类型也是unit8的别名
var a byte=‘a’ println打印出来是97(assic码转换)

(5)字符串类型—双引号表示字符串
var a string=“shuhaha”
ch :=‘a’
str :=“a” --包含了’a’ ‘\0’ 字符串结束标志
在go语言中,一个汉字占3个字符
len函数
字符串拼接可以用加号
`(反引号)括起的字符串为Raw字符串,即字符串在代码中的形式就是打印时的形式,它没有字符转义,换行也将原样输出。

字符和字符串区别
字符
1,单引号
2,字符往往都是只有一个字符,除了\n \t等转义字符
字符串
1,双引号
2,字符串可以有一个或者多个字符组成
3,字符串都是隐藏了一个结束符 ‘\0’
var str string=“hello word”
fmt.println(str[0],str[1]) 打印出来是字节类型

复数类型
自动推导式默认是complex128

格式化输出
%T 打印变量所属数据类型
%d 整型格式
%s 字符串格式
%c 字符格式
%f 浮点型格式
%v 自动格式匹配输出

输入

var a int
fmt.Scanf("%d",&a)  ---格式化输入
fmt.Scan(&a)  --最简单的输入

三,类型转换

类型转换用在不同但相互兼容的类型之间相互转换,不兼容类型不能相互转换
数据类型(变量) 数据类型(表达式)
类型转换时,
一般建议将低类型转换成高类型,比如float32和float64,就可以统一转换成64
整型和浮点型时,一般建议整型转换成浮点型

四,类型别名

type bigint int64 --给int64取了一个别名bigint
var a bigint=10
多个类型别名

type(
  long int64
  chr byte
)

五,if语句语法结构

if 条件表达式{   
   代码块
}

1,左括号与if在同一行
2, 条件表达式没有括号
3,if支持一个初始化语句,初始化语句和判断条件需要用分号分割
if a:=700 ; a>=700{
代码块
}

六,switch语句

switch 变量(表达式){  --和swith关键字在一行
  case 判断语句1:
    代码体
  case 判断语句2, 判断语句3:
    代码体
  defalut:   --都不满足上面条件时,走这里
    代码体
}

优点:
if 适合进行区间的判断,嵌套使用
switch 适合固定值 执行效率高,可以将多个满足相同条件的值放在一起
缺点:
1,if执行效率低
2,不建议使用嵌套

七,for语句语法

for  初始化条件; 判断条件; 条件变化{   --for后面不写任何东西,就是一个死循环 永远为真
 代码体
} 

迭代打印
关键字 range 会返回两个值,第一个返回值是元素的数组下标,第二个返回值是元素的值

str :="abc"
for i ,data := range str{
   fmt.Println(i, data)
}

最后一种方式:
for 条件{}

八,跳转语句

break 跳出循环,如果多层for循环,跳出最近的内循环,可以在switch和for循环中使用
continue 跳出本次循环,进入下一次循环,只能在for循环中使用

goto 跳转  --先例子中,不会打印b,会打印ac
  fmt.Println("a")
  goto End  //goto关键字,End是标签可以随意取取名
  fmt.Println("b")
End:
  fmt.Println("c")

九,函数

1,函数定义
func 函数名(参数列表) 返回值{
函数体
}

2,函数调用
在main函数中调用,调用方式:函数名(参数列表)
在这里插入图片描述

3,不定参数
1)不定参数放最后
2)函数调用,固定参数必须传值,不定参数根据需要决定是否传值
func sum(args …int){ …加上数据类型type
fmt.Println(args) --打印出来是一个列表
求和方法1:

sum :=0
  for i:=0;i<len(args);i++{
  sum +=args[i]   --根据下标取值求和
}

求和方法2:

sum :=0
for _,data := range args{
   sum +=data
}
}

不定参数调用:
func main(){
sum(args…: 1,2,3) --不定参数的使用
}

4,函数嵌套 —指在函数中调用另外一个函数
传递制定个数数据
在这里插入图片描述

5,函数返回值
函数返回使用return
1)返回一个值
在这里插入图片描述
2)返回多个值 --接收返回值与python一样
在这里插入图片描述

6,内存
1)栈区存储原理
内存相对于一个可执行程序来说,可以分为四个区:
代码区 :计算机指令(只读,共享)
数据区
堆区
栈区
在这里插入图片描述

栈区:用来存储程序执行过程中函数内部定义的信息和局部变量
函数执行调用完毕,就会从内存中释放

栈区存储原理:先进后出 后进先出 --比喻:进家门
2)函数返回值

3)函数嵌套使用

7,函数类型
函数名表示一个地址,函数在代码区的地址
直接打印函数时,打印出来的是一个函数地址

定义函数类型,给已存在的函数类型取别名
type 函数别名 func( )
在这里插入图片描述

8,函数作用域
局部变量
1定义在函数内部的变量,叫局部变量,局部变量的作用域,在函数内部有效
2不同函数,可以订单相同的局部变量名,互不影响
3变量先声明再使用,在函数内部变量名是唯一的
全局变量
1定义在函数外部的变量,叫全局变量,全部变量作用域,是在整个文件
2全局变量名不能和其他文件中的全局变量名重名
3全局变量名和局部变量名可以重名,但是尽量避免
4如果全局变量名和局部变量名相同,那么会使用局部变量(就近原则)

9,匿名函数 --没有名字的函数
在这里插入图片描述

匿名函数最主要的应用就是实现了闭包
闭包:

10,递归函数 调用函数自己本身
递归函数相同的结构
1跳出条件
2有调用函数自己本身

值类型:数据,结构体基本类型都是值类型,改变副本不影响原有值
引用类型:字典map和切片是引用类型,改变副本影响原有值

复合数据类型

一,数组:

数组定义
指同一系列同一类型数据的集合 ,数组的长度是固定的
定义方式: var 数组名 [长度]类型
int float 默认输出0
string 默认输出空字符
bool 默认输出false
数组初始化:
全部初始化,自动推导,部分初始化,指定某个元素初始化 …通过初始化确定长度
总结:
1,数组长度是一个常量
2,数组下标越界报错
3,数组名无法接收数据
4,两个数组类型相同,个数相同,可以赋值
5,数组名表示整个数组,数组名对应地址也是第一个元素的地址

随机数使用包:math/rand
rand.seed(1) 创建随机数种子

数组作为函数参数是值传递,也可以作为函数返回值
实参和形参是两个不同的内存地址,在函数调用结束后,内存回收,不会影响主函数中实参的值

二维数组
定义方式:
常规定义:var arr [2][3]int
自动推导:b :=[2][3]int{{1,2},{3,4}}

二,切片

注意:切片不是数组,只是类似数组但不固定长度
切片有长度len()和容量cap(),容量是已经开辟的空间
1,定义方式:
var a []int --打印出来是一个空切片[]
var a []int=int{1,2,3}
a :=[]int{1,2,3,4}
a :=make([]int,2,3) 2是长度,3是容量 ,注: 长度<=容量,容量可以省略掉,默认长度=容量
空切片指向内存地址编号为0的空间,切片名本省就是一个地址
当使用append追加数值时,切片地址可能会发生改变

2,切片扩容:
追加数据时,长度超过容量,自动扩容
一般容量*2扩容,如果超过1024字节,每次扩容为上一次的1/4,容量扩容是一个偶数

3,切片截取:
[low:higth:max],或者[low:higth]–这个时候的max默认与原切片容量cap一样
切片后的len=higth-low,
切片后的cap=max-low ,当使用[low:higth]时,切片后的cap=原始切片的容量cap-low
截取切片后的值还是原始切片中的值–都是指向同一个地址

4,切片拷贝copy
copy(s1,s2):将s2拷贝到s1 --从初始位置开始复制
使用copy进行拷贝,在内存中存储两个独立的切片内容,如果任意一个发生修改,不会影响另外一个

5,切片作为函数参数
切片作为函数参数,是引用传递(切片名本身是一个地址,所以相当于是给函数传了一个地址)
解释:实参传递给形参是一个地址,指向的是同一内存地址,操作的是相同的数据,形参可以改变实参的值

切片在内存中存储如果该空间没有指向,则会进行消回
注意:
如果在函数内部使用append追加数据时,形参地址发生改变,就不会指向实参的地址,所以就不会改变实参的值
因为当使用append追加数值时,切片地址可能会发生改变

三,字典map

1,定义方式:
var a map[int] string
a =map[int]string{1:“ss”,2:“aa”} --初始化
b :=make(map[int]string,3) --3是指容量大小,可以不写
c :=map[int] string{1:“ss”,2:“aa”} 自动推倒式
在字典中不能使用cap函数,如果需要差字典中键值对数量,只能使用len函数
键是唯一的,值可以重复;map中的key类型必须支持==或者!=,一般建议写基本类型(切片,函数等都不能作为key)
m :=make(map[string][3]int) --key是string类型,值是数组类型
赋值:m[]
2,操作
map中数据是无序的
可以通过for循环取值和赋值
在map中如果没有提供key找到具体的值,打印value类型的默认值
d=map[int]string{1:“ss”,2:“aa”}
value,ok:=d[1] --ok的值是ture,用来判断键值是否存在
delete(d,2) ,删除map中的元素,根据key进行删除
字典作为函数参数,是引用传递,形参和实参指向相同的内存地址,修改形参会影响实参的值

四,结构体

自定义类型和类型别名
type newInt int //自定义类型,打印:main.newInt(表示 main 包下定义的 newInt 类型)
type newInt=int //类型别名,打印:int

1,定义
结构体定义在函数外部,构体名大小写,大写可以支持在其它文件中使用,小写仅在当前文件中支持
type 结构体名 struct{
//结构体成员列表
成员名 数据类型
}
如:
type student struct{
id int
name string
age int
}

2,结构体类型
结构体字段的类型可以是:基本数据类型,切片,map,结构体
如果几个结构体的字段类型是:指针/切片/map,那零值都是nil,即还没有分配空间,如果需要使用这样的字段,需要先使用make分配空间后才能使用

3,结构体实例化
只有当结构体实例化时,才会真正地分配内存
1,顺序初始化,每个成员必须初始化且按顺序初始化:
var s1 student=student{1,“jjj”,40}
2,自动推导类型
a :=student{3,“kskk”,30}
3,指定成员赋值(键值对初始化),最后一个属性的“ , ”要加上
var s2 student=student{id:3,age:40,}
4,使用 变量.属性 的方式赋值
var s3 student
s3.id=4
s3.age=99
5,go中支持对结构体指针直接使用.来访问结构体的成员
var s4 = new(student)
s4.id=4 --这里底层相当于 (*s3).id=4
另外一种结构体指针的使用:结构体指针进行键值对初始化
s5 := &student{ id:5, name: “hah”, }

4,操作
结构体名本身就指向了第一个成员所在的地址
结构体比较,
同样类型的两个结构体是可以进行比较的,支持==的比较(不支持><的比较)
结构体赋值
同样类型的两个结构体之间是可以赋值的

5,结构体数组和切片
在这里插入图片描述

获取结构体信息:
arr[1]
修改结构体成员指定信息:
arr[1].score = 97
结构体切片 添加数据:
arr = append(arr, Student{4, “袁华”, 100})
结构体数组作为函数参数,是指传递
结构体切片作为函数参数 地址传递 (引用传递)

6,结构体map
1,将结构体作为map中的value值,map中的数据不建议排序操作
type hero struct {
name string
age int
power int
}
m := make(map[int]hero)
在这里插入图片描述

2,结构体切片作为map中的value值
m := make(map[int][]hero)
在这里插入图片描述

结构体map作为函数参数,是引用传递

7,结构体和json的转换–使用json包
私有属性不能被json包访问
使用“%#v”能打印出详细的结构体,在结构体打印中可以使用该方法
(1)结构体对象转化成 Json 字符串
s1 :=student{3,“kskk”,30}
var s, _ = json.Marshal(s1)
jsonStr := string(s)
(2)Json 字符串转换成结构体
var jsonStr = {"ID":1,"Gender":"男","Name":"李四","Sno":"s0001"}
var student Student
err := json.Unmarshal([]byte(jsonStr), &student)
(3)结构体标签Tag
Tag 是结构体的元信息,可以在运行的时候通过反射的机制读取出来。 Tag 在结构体字段的 后方定义,由一对反引号包裹起来,具体的格式如下:
key1:"value1" key2:"value2"
type Student struct {
ID int json:"id" //通过指定 tag 实现 json 序列化该字段时的 key
}

五,面向对象

1,匿名字段
匿名字段(嵌入字段):在结构体定义中,只提供定义类型,而不写字段名的方式,当匿名字段也是一个结构体时,这个结构体所拥有的全部字段都会被隐式的引入了当前定义的这个结构体中
go语言中没有继承,但是可以通过匿名字段实现继承功能(结构体嵌套结构体)
在这里插入图片描述

初始化方式:
顺序初始化,按照结构体定义顺序进行初始化赋值
自动推倒类型
指定初始化成员,没有初始化的部分使用默认值(指定初始化时可以不安顺序赋值)

2,匿名字段使用
当访问结构体成员时会现在结构体中查找该字段,找不到时会再去匿名字段中查找
(1)匿名字段同名成员
子类和父类结构体有相同的成员名时,默认赋值给子类,采用就近原则。
给匿名同名成员赋值,需要显示调用赋值,如:s1.Person.name=“aaa” (给父类Person的name字段赋值)
(2)其它匿名字段–非结构体类型
所有的内置类型和自定义类型都是可以作为匿名字段的
(3)其它匿名字段–结构体指针类型

使用指针类型为匿名字段,不能使用xx.xx进行赋值
初始化:s1 := Student{&Person{“mike”,‘m’,18},1,“bj”}
声明变量:使用new新开辟一个空间
在这里插入图片描述

内存理解:
在这里插入图片描述

3.多重继承
方式一:结构体成员为多个匿名字段,初始化赋值时需要按照继承的顺序进行赋值,否则会报错
在这里插入图片描述

方式二:子孙三代继承方式

3.对象方法的创建和使用
方法
一个方法是一个和特殊类型关联的函数,对象中会包含一些函数,这种带有接收者的函数,称为方法
在Go语言中,可以给任意自定义类型(包括内置类型,但不包括指针类型)添加相应的方法
函数定义
func 函数名 (参数列表) 返回值列表 {
代码体
}
方法定义 ---------⽅法总是绑定对象实例,并隐式将实例作为第⼀实参
func (接收者对象)方法名 (参数列表) 返回值列表 {
代码体
}
结构体类型可以作为对象类型
.调用:对象.方法 包.函数 结构体.成员
对象的方法名和函数名可以重名,但是相同的对象方法不能重名
方法名一样,接受者不一样,方法也就不一样;所以对象不同,方法名相同,不会冲突

在方法调用中,如果方法接收者是普通类型是值传递,原始值不会改变;如果方法接收者是指针类型是地址传递,原始值可以被改变。
建议在定义方法时将接收者指定为指针类型(调用时候接收者可以是指针类型或者普通类型,此时指针类型和普通类型,表示的是相同对象的类型)
在这里插入图片描述

方法继承
如果匿名字段实现了一个方法,那么包含这个匿名字段的struct也能调用该方法
子类可以继承父类,可以继承父类的属性和方法;父类不能继承子类的属性和方法

方法重写
子类方法名与父类方法名同名,则在子类中将该方法重写
执行调用时采用就近原则,调用的是子类的方法,s.PrintInfo
调用父类方法需要显示调用, s.person09.PrintInfo

方法值和方法表达式
类似函数进行赋值和传递一样,方法也可以进行赋值和传递。根据调用者不同,分为两种表现形式:方法值和方法表达式
方法值和方法表达式区别:
1,方法值是一个隐式传递,隐藏的是接受者,并且需要绑定实例(对象)
2,方法表达式是一个显式传参

%p可以打印变量所在地址

六,指针

前言:Go 语言中对于引用类型的变量,我们在使用 的时候不仅要声明它,还要为它分配内存空间,否则我们的值就没办法存储。而对于值类型 的声明不需要分配内存空间,是因为它们在声明的时候已经默认分配好了内存空间。而引用类型需要手动分配空间(一般使用make函数实现)

值类型:数据,结构体基本类型都是值类型,改变副本不影响原有值
引用类型:字典map和切片是引用类型,改变副本影响原有值

1,指针变量定义,指针必须创建内存后才能使用
var p *int //定义一个指针变量
p = &i //把变量i 地址复制指针变量p

2,空指针
var p *int
默认值:定义一个指针变量没有赋值时(),默认时nil

3,野指针(没有指向,直接操作)
指针变量指向一个未知的空间,会报错,程序中不允许出现野指针

4,new函数和make函数,都是开辟一个内存空间。–一般情况下不适用new实现
区别:
(1)make 只用于 slice、map 以及 channel 的初始化,返回的还是这三个引用类型本身
(2)new 用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指

var p *int
p = new(int) --开辟一个整型内存空间,go有垃圾回收机制,能自动释放空间
*p = 57

指针作为函数参数,是地址传递
&变量 取地址操作 引用运算符
*指针变量 取值操作 解引用运算符

概念1:数组指针
arr := [3]int{1, 2, 3}
var p *[3]int 定义指针,指向数组 数组指针
p = &arr 指针和数组建立关系
自动推导类型创建数组指针
p := &arr --指针变量和要存储数据类型要相同
通过指针操作数组
格式1:(*数组指针变量)[下标] = 值
(p)[0] = 111 --运算优先级:先p拿到数组的地址,再[0]拿到这个数组下标为0的值
格式2:数组指针变量[下标]
p[1] = 222
在这里插入图片描述

arr := [5]int{1, 2, 3, 4, 5}
指针变量和要存储数据类型要相同
p1 := &arr --数值指针
p2 := &arr[0] --指针变量
p1和p2在内存中指向相同的地址

概念2:指针数组
数组元素是指针类型
定义:
var arr [3]*int = [3]*int{&a, &b, &c}
修改值:
arr[1] = 200 --运算优先级:先计算arr[1] ,再得到值

二维指针数值

概念3:切片指针
s := []int{1,2,3,4,5}
p := &s 指针和切片建立联系(此时打印的p和s地址不一样)
另外一种定义方式:var p *[]int

通过指针间接操作切片元素
(*p)[0] = 111 –
p[1] = 222 --不支持这种操作方式

切片指针作为函数参数,是地址传递

概念4:结构体指针

概念5:多级指针
一级指针 指向变量的地址 var p *int
二级指针 指向一级指针的地址 var pp **int
修改
通过二级指针链接修改一级指针的值
通过二级指针间接修改变量的值
引用运算符,不能连续使用

指针用途:
1,指针做函数参数,实现形参改变实参
2,数据比较大时,会使用指针作为形参

七,接口

(1)接口定义和使用
1,接口是一种规范与标准,只是做约定的,只规定做哪些事情,但是不管怎么做
2,一般在定义结构体前面先定义接口,一般以er结尾,根据接口实现功能
3,接口也是一种数据类型,是一组函数的组合,接口不能包含任何变量
4,如果接口里面有方法的话,必须要通过结构体或者通过自定义类型实现这个接口,一般使用接口提实现
5,一个变量要实现某个接口的话,就必须得实现这个接口中的所有方法,否则会有问题;但是这个变量可以有不属于这个接口的方法

格式:
type Humaner interface {
//方法 方法的声明
sayhi()
}

接口是虚的,方法是实的
接口负责定义规则,而方法负责实现规则
接口定义的规则,在方法中必须有对应的定义实现
将对象赋值给接口,必须满足接口中的方法的声明格式
例子:
var h Humaner
tea := teacher11{“老王”,28,“物理”}
h = &tea --将tea的地址赋值给接口h
h.sayhi()

多态的实现 --接口的好处是可以实现多态
多态就是同一个接口,使用不同的实例而执行不同操作,所谓多态指的是多种表现形式
定义一个函数,将接口作为函数参数,实现多态。(表面上看是调用了同一个函数,但是因为将接口作为了函数参数,所以实则实现了不同的表现形式)

接口的继承和转换
接口的继承也是使用匿名字段方式实现
将一个接口赋值给另外一个接口,而且超集包含所有子集的方法

(2)空接口
var i interface{}
空接口(interface{})不包含任何的方法,表示没有任何约束,接口类型可以接收任意类型的数据,所以可以定义空接口来实现存储所有类型的数据
当函数可以接受任意的对象实例时,我们会将其声明为interface{},最典型的例子是标准库fmt中PrintXXX系列的函数
golang中空接口也可以直接当作类型来使用,可以表示任何类型
空接口作为函数参数:
func Test(arg …interface{}) { —函数可以接收任意个数,任意类型的参数
//代码体
}

map的值实现空接口:
var stuadent=make(map[string]interface{}) --可以保存任意值的字典

切片实现空接口:
var i []interface{} --空接口类型的切片,这个切片可以追加任何类型的数据,包括函数

空接口的类型断言
1,comma-ok断言
使用语法:
值,值的判断 := 接口变量.(数据类型)
value, ok := element.(T)
解释:value就是变量的值,ok是一个bool类型,element是interface变量,T是断言的类型。如果element里面确实存储了T类型的数值,那么ok返回true,否则返回false
2,switch测试
value:= element.(type) --直接结合switch语句使用

切片实现空接口后的成员获取
var userinfo =make(map[string]interface{})
userinfo[“hobby”]=[]string{“哈哈”,“亚亚”}
如果要获取成员值"哈哈",直接使用userinfo[“hobby”][0]无法获取
正确使用方法是:–结合属性.(数据类型)使用
hobby2, _ :=userinfo[“hobby”].([]string)
hobby2[0]

(3)结构体的值接收者和指针接收者实现接口的区别
值接收者:
结构体中的方法是值接收者,那么实例化后的结构体的值类型和指针类型都可以赋值给接口变量
指针接收者:
结构体中的方法是指针接收者,那里实例化后的结构体指针类型可以赋值给接口变量,结构体值类型不可以赋值给接口变量

(4)一个结构体实现多个接口

(5)接口嵌套
接口与接口间可以通过嵌套创造出新的接口

八,异常处理

1,error接口,需要导入errors,

2,panic函数,当程序遇到panic是自动终止(常规不需要主动调用该函数,系统会自动调用该函数)
3,延迟调用defer
defer后面的代码会被延迟调用处理,应用场景:文件操作
defer语句只能出现在函数内部

一个函数有多个defer语句 它们以后进先出的顺序执行
常规情况下,代码从上到下执行,当发生错误时会停止后面代码的执行,使用defer后,即使函数或者某个延迟调用发生错误,其它调用或者代码依旧会被执行
defer要延迟执行的函数时,该函数所有的参数都需要确定其值
在函数前面使用defer,即使没有立即执行,但是因为代码是从上到下执行的,其实已经完成了参数传递等操作,只是没有执行而已

4,recover函数
recover使用场景:防止程序崩溃
recover()只能在defer函数中使用
defer func() {
if err:=recover();err!=nil { --没有程序报错时,recover()的值时空nil
fmt.Println(err)
}
}() //匿名函数

九,字符串处理

1,字符串处理函数–使用strings包
查找
1.bool类型 := strings.Contains(被查找字符串,查找字符串),一般用于模糊查找
2.int类型 := strings.Index(被查找字符串,查找字符串)
分割
[]string类型 := strings.Spilt(切割字符串,标志)
组合
string类型 := strings.Join(字符串切片,标志)
重复
string类型 := strings.Repeat(字符串,次数)
替换
string类型 := strings.Replace(字符串,被替换字符串,替换字符串,次数)
去掉内容
string类型 := strings.Trim(字符串,去掉字符串)
[]string类型 := strings.Fields(字符串)

2,字符串类型转换 -strconv包
(1)字符串转换成字符切片 --强制类型转换
slice := []byte(str)

(2)字符切片转换成字符串
slice := []byte{‘h’,‘e’,‘l’,‘l’,‘o’,97}
str :=string(slice)

(3)将其他类型转成字符串----Format
–bool类型转换成字符串
str := strconv.FormatBool(true) --FormatBool(布尔值)转成字符串的"false",“true”
–整型转换成字符串
str := strconv.FormatInt(120,10) --FormatInt(整型,进制)进制一般是2,6,8,10
–浮点型转换成字符串
str:= strconv.FormatFloat(3.14159,‘f’,4,64) --FormatFloat(浮点型小数,打印方式为’f’,小数位数,以float64处理),打印出来的字符串是四舍五入了:3.1416
–数值转换成字符串
str := strconv.Itoa(123) --Itoa(整型) ,转换成字符串“123”
功能等同于:str := strconv.FormatInt(123,10)

(3)字符串转换成其它类型----Parse
–字符串转换成bool类型
b,err := strconv.ParseBool(“true”) --当err为空时转换成功,当转换不成功时b的值是false
–字符串转换成整型
v,err := strconv.ParseInt(“abc”,10,64) --ParseInt(字符串,转换的进制数,int的类型64还是32) ,当转换不成功时v的值是0
–字符串转换成浮点型
v,err := strconv.ParseFloat(“3.14159”,64)—ParseFloat字符串,int字节类型),当转换不成功时v的值是0
–字符串转转换成数值
v,err:=strconv.Atoi(“122323”) --当转换不成功时v的值是0
功能等同于:v,err := strconv.ParseInt(“abc”,10,64)
(3)将其他类型转成字符串,并且添加到字符切片里—Append 系列
slice := make([]byte,0,1024)
slice = strconv.AppendBool(slice,false)
slice = strconv.AppendInt(slice,123,2)
slice = strconv.AppendFloat(slice,3.14159,‘f’,4,64)
slice = strconv.AppendQuote(slice,“hello”)
fmt.Println(slice) --打印字符切片
fmt.Println(string(slice)) --打印出一个字符串

十,文本文件操作–使用os包

1,创建文件-----使用Create函数时,如果文件已经存在,则会先删除文件中已有数据
fp,err := os.Create(文件名)—文件名可以写绝对路径和相对路径,err 不为空时创建失败;返回文件指针,错误信息
创建成功了需要关闭文件
defer fp.Close() --延迟调用,打开文件最后一定要关闭文件

2,读写文件
一般在写路径时可以使用/正斜杠代替\反斜杠
(1)写入
fp.WriteString(“hello world\r\n”) --参数是字符串
count,err1 := fp.Write([]byte(“hello world”)) --参数是字符切片,返回值:写入的字符切片长度,错误信息
指定位置写入数据:
count,err:=fp.Seek(0,io.SeekEnd) --获取文件起始到结尾有多少个字符
fp.WriteAt([]byte(“hello world”),10) --参数是字符切片,指定位置写入
(2)打开文件
fp,err := os.Open(“D:/a.txt”) --Open函数只读方式打开,返回文件指针,错误信息
os.OpenFile(文件名,打开方式,打开权限)

(3)读取文件
块读取
buf:= make([]byte,1024*2)
n,err:=fp.Read(buf) --参数是字符切片,n 读取的长度,err值为io.EOF,代表读到了文件的结尾
str :=string(buf[:n] -读取出来转换成字符串,n 读取的长度
行读取—按行读取
//需要先创建文件的缓冲区
r := bufio.NewReader(fp)
slice,err:= r.ReadBytes(’\n’) --读取出来是字符,重复执行多次可以读取多行
str :=string(slice)
常规操作:使用for循环读取,读取到最后io.EOF则退出循环
str ,err2 := r.ReadString(’\n’) --读取出来是字符串

十一,闭包

闭包写法:函数里嵌套一个函数,最后返回里面的函数

全局变量特点:常驻内存,污染全局
局部变量特点:不常驻内存,不污染全局
闭包:可以让一个变量常驻内存,可以让一个变量

十二,时间

1,时间格式化

2006 1 2 3 4 5
"时"使用3–12小时制 , "时"使用15–24小时制
2,获取当前时间戳

3,时间戳转换成字符串

4,日期字符串转换成时间戳

十三,go中的包

分成三种:1,系统内置包 2,自定义包 3,第三方包
(1)Golang 包管理工具 go mod
的 golang 项目文件要放在了 yaya这个文件夹,这个时候我们需要在 itying 文件夹 里面使用 go mod 命令生成一个 go.mod 文件
命令为: go mod init yaya
(2)Golang 中自定义包
每个go文件都必须在第一行声明该文件归属的包 :package 包名

设置包别名
import 别名 “包的路径”

golang中的init()初始化函数,init函数是先于main函数自动调用,且么有参数也没有返回值
多个包中的init函数执行顺序

(3)Golang 中使用第三方包

十四,goroutine

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值