Go的第9课——特殊语句&指针的基本应用

defer语句

go语言中的 defer 语句会将其后面跟随的语句进行延迟处理。在 defer 归属的函数即将返回时,将延迟处理的语句按 defer 定义的逆序进行执行,也就是说,先被 defer 的语句最后被执行,最后被 defer 的语句,最先被执行。

下面给个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import "fmt"

func main() {
fmt.Println("start")
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("end")
}
/*
start
end
3
2
1
*/

可以发现 defer 申明的语句一律是在最后执行,并且先被 defer 的语句最后执行。

它可以有以下用途:

  • 关闭文件句柄
  • 锁资源释放
  • 数据库连接释放

这样就可以在打开一个文件句柄的时候马上用 defer 声明关闭而不用写到函数最后才关闭,避免写到后面忘记去关闭这个文件句柄了。

init函数

golang 有一个特殊的函数 init 函数,先于 main 函数执行,实现包级别的一些初始化操作。

函数特点

  • init 函数先于 main 函数自动执行,不能被其他函数调用;
  • init 函数没有输入参数、返回值;
  • 每个包可以有多个 init 函数;
  • 包的每个源文件也可以有多个 init 函数,这点比较特殊;
  • 同一个包的 init 执行顺序,golang没有明确定义,编程时要注意程序不要依赖这个执行顺序。
  • 不同包的 init 函数按照包导入的依赖关系决定执行顺序。

golang初始化顺序

init 函数先于 main 去执行的,全局变量初始化会在 init 之前执行,如果初始化依赖一个函数,那么这个函数会被最优先执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import "fmt"

func InitVar() int {
fmt.Println("InitVar")
return 0
}

var n = InitVar()

func init() {
fmt.Println("init")
}
func main() {
fmt.Println("start")
fmt.Println("end")
}
/*
InitVar
init
start
end
*/

指针

Go语言中的函数传参都是值拷贝,当我们想要修改某个变量的时候,我们可以创建一个指向该变量地址的指针变量。传递数据使用指针,而无须拷贝数据。

类型指针不能进行偏移和运算。

Go语言中的指针操作非常简单,只需要记住两个符号:&(取地址)和*(根据地址取值),和 C 一样一样的。

指针地址和指针类型

每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。G。语言中使用&字符放在变量前面对变量进行取地址操作。Go语言中的值类型(int、float、bool、string、array、struct)都有对应的指针类型,如:*int、*int64、*string等。在

在声明指针的时候也需要反一下

1
var identifier *type

创建一个 type 类型的指针 identifier。

前面说过,函数传参只是简单的值复制,不会影响原值,但是如果传指针类型,内部又对指针所指向的地址进行了操作,那就会导致原值发生变化。

指向数组的指针

go 语言的指针还是没有 C 语言那么灵活,它不支持与整型加法运算。而且指向数组的指针也比较麻烦,我得定义的一一模一样才能指。[3]int[]int 它不是同一个类型,不能乱指,我非要指的话就得转切片出来指,不得不说有点麻烦。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import "fmt"

func main() {
var n = [3]int{1, 2, 3}
var p *[]int
var s []int = n[:]
p = &s
fmt.Printf("%v", (*p)[1])
}
/*
2
*/

而且发现了一个比较奇怪的现象,就是说我切片如果用数组赋值,那么它将会跟数组绑定到一起,数组的元素改变切片的元素一样会改变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import "fmt"

func main() {
var n = [3]int{1, 2, 3}
var p *[]int
var s []int = n[1:]
p = &s
fmt.Printf("%v\n", (*p)[1])
(*p)[1] = 9
fmt.Println(n)
fmt.Println(s)
}
/*
3
[1 2 9]
[2 9]
*/