本文省去基本定义
文章目录
- 1. 函数
- 1.1 闭包
- 1.2 延迟执行语句(defer)
- 1.3 处理运行时发生的错误
- 1.4 宕机(panic)——程序终止运行
- 1.5 宕机恢复(recover)——防止程序崩溃
- 2. 结构体
- 2.1 结构体的实例化
- 2.2 方法
- 2.3 结构体的继承
- 2.4 实现接口
1. 函数
1.1 闭包
闭包是一个函数和其相关环境组合的一个整体
函数+引用环境=闭包
能通过指针调用匿名函数或者函数是实现闭包的关键
1 2 3 4 5 6 7 8 9 10 11 12 | func main() { accumulate := Accumulate(1) //返回一个指向返回函数的指针 fmt.Printf("%T", accumulate) fmt.Println(accumulate())//通过指针调用Accumulate内的匿名函数 fmt.Println(accumulate()) } func Accumulate(i int) func() int { return func() int { i++ return i } } |
1.2 延迟执行语句(defer)
先被defer的语句最后被执行,最后被defer的语句,最先被执行。
用法: 使用延迟执行语句在函数退出时释放资源
1 2 3 4 5 | func main() { defer fmt.Println("first") fmt.Println("second") defer fmt.Println("third") } |
1.3 处理运行时发生的错误
Go语言的设计者认为其他语言的异常机制已被过度使用,上层逻辑需要为函数发生的异常付出太多的资源。
error是Go系统声明的接口类型,代码如下:
1 2 3 | type error interface{ Error() string } |
所有符合Error() string格式的方法,都能实现错误接口。Error()方法返回错误的具体描述,使用者可以通过这个字符串知道发生了什么错误。
1 2 3 4 5 6 7 8 9 10 11 | func main() { fmt.Println(div(0, 1)) fmt.Println(div(0, 0)) } func div(a, b int) (int, error) { if b == 0 { return 0, errors.New("made,除了个0!") } return a / b, nil } |
1.4 宕机(panic)——程序终止运行
手动触发panic
1 2 3 | func main() { panic("触发异常。。。") } |
其次:
1 2 3 4 5 | func main() { defer fmt.Println("beforepanic") panic("触发异常。。。") defer fmt.Println("afterpanic") } |
当panic()触发的宕机发生时,panic()后面的代码将不会被运行,但是在panic()函数前面已经运行过的defer语句依然会在宕机发生时发生作用。
1.5 宕机恢复(recover)——防止程序崩溃
这玩意真难用:
例1:
1 2 3 4 5 6 7 8 9 10 11 12 | func main() { defer func() { //recover() //可以打印panic的错误信息 //fmt.Println(recover()) if err := recover(); err != nil { //产生了panic异常 fmt.Println(err) } }() //别忘了(), 调用此匿名函数 panic("0000") } |
例2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | package main import "fmt" func testa() { fmt.Println("aaaaaaaaaaaaaaaaa") } func testb(x int) { //设置recover,recover只能放在defer后面使用 defer func() { //recover() //可以打印panic的错误信息 //fmt.Println(recover()) if err := recover(); err != nil { //产生了panic异常 fmt.Println(err) } }() //别忘了(), 调用此匿名函数 var a [10]int a[x] = 111 //当x为20时候,导致数组越界,产生一个panic,导致程序崩溃 } func testc() { fmt.Println("cccccccccccccccccc") } func main() { testa() testb(20) //当值是1的时候,就不会越界,值是20的时候,就会越界报错。 testc() } |
2. 结构体
2.1 结构体的实例化
- 结构体本身是一种类型,可以像整型、字符串等类型一样,以var的方式声明结构体即可完成实例化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | type Student struct { name string age int } func main() { var student Student fmt.Printf("%T\n",student) fmt.Printf("%T\n",&student) student.name="lisi" student.age=11 fmt.Println(student) } |
- Go语言中,还可以使用new关键字对类型(包括结构体、整型、浮点数、字符串等)进行实例化,结构体在实例化后会形成指针类型的结构体。
1 2 3 4 5 6 7 8 9 | func main() { student := new(Student) fmt.Printf("%T\n",student) fmt.Printf("%T\n",&student) student.name="lisi" student.age=11 fmt.Println(student) } |
在Go语言中,访问结构体指针的成员变量时可以继续使用“.”。这是因为Go语言为了方便开发者访问结构体指针的成员变量,使用了语法糖(Syntactic sugar)技术,将ins.Name形式转换为(*ins).Name。
- 在Go语言中,对结构体进行“&”取地址操作时,视为对该类型进行一次new的实例化操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | func main() { //student是一个指针 student := &Student{ name: "zhansan", age: 0, } fmt.Println(student) fmt.Printf("%T\n", student) fmt.Printf("%T\n", &student) fmt.Printf("%T\n", *student) student.name = "lisi" student.age = 11 fmt.Println(student) } |
2.2 方法
Go语言中的方法(Method)是一种作用于特定类型变量的函数。这种特定类型变量叫做接收器(Receiver)。
这里多了一个接收器的概念:
接收器——方法作用的目标
重点区别一下:(student *Student)与(student Student)的区别
- 理解指针类型的接收器
指针类型的接收器由一个结构体的指针组成,更接近于面向对象中的this或者self。
由于指针的特性,调用方法时,修改接收器指针的任意成员变量,在方法结束后,修改都是有效的。
1 2 3 4 5 6 7 8 9 10 | func (this *Student) init() { this.name="init" this.age=21 } func main() { var stu Student fmt.Println(stu) stu.init() fmt.Println(stu) } |
1 2 3 4 5 6 7 8 9 10 | func (this Student) initNoPointer() { this.name="noPointerInit" this.age=21 } func main() { var stu Student fmt.Println(stu) stu.initNoPointer() fmt.Println(stu) } |
- 理解非指针类型的接收器
当方法作用于非指针接收器时,Go语言会在代码运行时将接收器的值复制一份。在非指针接收器的方法中可以获取接收器的成员值,但修改后无效。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | func (this Student) initNoPointerReturn() Student { this.name = "noPointerInit" this.age = 21 + this.age return this } func main() { var stu Student stu.age = 11 fmt.Println(stu) initNoPointerReturn := stu.initNoPointerReturn() fmt.Println(initNoPointerReturn) fmt.Println(stu) } |
在计算机中,小对象由于值复制时的速度较快,所以适合使用非指针接收器。大对象因为复制性能较低,适合使用指针接收器,在接收器和参数间传递时不进行复制,只是传递指针。
2.3 结构体的继承
组合思想
2.4 实现接口
想要实现接口只需要方法格式与接口内的方法结构一致即可
略