Go Study Day03 - 函数
子车轻罗 2019/7/13 go学习提升
# 函数
# 函数的定义
# 基本格式
func f1() {
fmt.Println("Hello 沙河!")
}
1
2
3
2
3
# 参数的格式
- 有参数的函数
func f2(name string) {
fmt.Println("Hello", name)
}
1
2
3
4
2
3
4
- 参数类型简写
// 参数类型简写
func f4(x, y int) int {
return x + y
}
1
2
3
4
2
3
4
- 可变参数
// 可变参数
func f5(title string, y ...int) int {
fmt.Println(y) // y是一个int类型的切片
return 1
}
1
2
3
4
5
6
2
3
4
5
6
# 返回值的格式
- 有返回值
// 带参数和返回值的函数
func f3(x int, y int) int {
sum := x + y
return sum
}
1
2
3
4
5
2
3
4
5
- 命名返回值
// 命名返回值
func f6(x, y int) (sum int) {
sum = x + y // 如果使用命名的返回值,那么在函数中可以直接使用返回值变量
return // 如果使用命名的返回值,return后面可以省略返回值变量
}
1
2
3
4
5
2
3
4
5
- 多返回值
// Go语言中支持多个返回值
func f7(x, y int) (sum int, sub int) {
sum = x + y
sub = x - y
return
}
1
2
3
4
5
6
2
3
4
5
6
# 变量作用域
- 全局作用域
- 函数作用域
- 先在函数内部找变量,找不到往外层找
- 函数内部的变量,外部是访问不到的
- 代码块作用域
var x = 100 // 定义一个全局变量
// 定义一个函数
func f1() {
// x := 10
name := "理想"
// 函数中查找变量的顺序
// 1. 先在函数内部查找
// 2. 找不到就往函数的外面查找,一直找到全局
fmt.Println(x, name)
}
func main() {
f1()
// fmt.Println(name) // 函数内部定义的变脸只能在该函数内部使用
// 语句块作用域
if i := 10; i < 18 {
fmt.Println("乖乖上学")
}
// fmt.Println(i) // 不存在i
for j := 0; j < 5; j++ {
fmt.Println(j)
}
// fmt.Println(j) // 不存在j
}
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
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
# 高阶函数
函数也是一种类型,它可以作为参数,也可以作为返回值。
// 函数也可以作为参数的类型
func f3(x func() int) {
ret := x()
fmt.Println(ret)
}
func ff(a, b int) int {
return a + b
}
// 函数还可以作为返回值
func f5(x func() int) func(int, int) int {
return ff
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 匿名函数
没有名字的函数,多用在函数内部定义函数时使用。
func main() {
// 函数内部没有办法声明带名字的函数
// 匿名函数
f1 := func(x, y int) {
fmt.Println(x + y)
}
f1(10, 20)
// 如果只是调用一次的函数,还可以简写成立即执行函数
func(x, y int) {
fmt.Println(x + y)
fmt.Println("Hello world!")
}(100, 200)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 闭包
# defer
defer延迟调用,会把defer后面的语句延迟调用
把当时的状态都保存
defer多用于释放资源
多个defer存在时,按照先进后出的方式去执行。
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
func main() {
a := 1
b := 2
defer calc("1", a, calc("10", a, b))
a = 0
defer calc("2", a, calc("20", a, b))
b = 1
}
// 1. a:=1
// 2. b:=2
// 3. defer calc("1", 1, calc("10", 1, 2))
// 4. calc("10", 1, 2) // "10" 1 2 3
// 5. defer calc("1", 1, 3)
// 6. a = 0
// 7. defer calc("2", 0, calc("20", 0, 2))
// 8. calc("20", 0, 2) // "20" 0 2 2
// 9. defer calc("2", 0, 2)
// 10. b = 1
// calc("2", 0, 2) // "2" 0 2 2
// calc("1", 1, 3) // "1" 1 3 4
// 最终的答案:
// "10" 1 2 3
// "20" 0 2 2
// "2" 0 2 2
// "1" 0 3 3
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
32
33
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
32
33
# 内置函数
# panic和recover
func funcA() {
fmt.Println("a")
}
func funcB() {
// 刚刚打开数据库连接
defer func() {
err := recover()
fmt.Println(err)
fmt.Println("释放数据库连接...")
}()
panic("出现了严重的错误!!!") // 程序崩溃退出
fmt.Println("b")
}
func funcC() {
fmt.Println("c")
}
func main() {
funcA()
funcB()
funcC()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 标识符
标识符:变量名 函数名 类型名 方法名
Go语言中如果标识符首字母是大写的,就表示对外部包可见(暴露的,公有的).
# 自定义类型和类型别名
type MyInt int // 自定义类型
type newInt = int // 类型别名
1
2
2
类型别名只在代码编写 过程中有效,编译完之后就不存在,内置的byte
和rune
都属于类型别名.