第六篇:面向过程编程-函数及错误处理
目录
一、函数的定义
二、函数的调用
三、匿名函数与闭包
四、函数作为值传递
五、错误处理
1、error
2、延迟执行defer关键字(当defer所处的函数退出前会调用defer关键字后面的函数)
3、Panic(恐慌)和Recover(恢复)
一、函数的定义
Go语言里一个函数由六部分组成:func关键字、函数名、参数列表、返回值列表、函数体、返回值。
(清单1.1)
func hey(v1 int, v2 int) (r1 int, r2 int) {
if v1 < 0 || v2 < 0 {
return 0, 0
} else {
return v1, v2
}
}
如果参数列表和返回值列表有多个变量的类型一样,它们就可以连起来一块儿给类型。如上面的函数和下面是一样的:
(清单1.2)
func hey(v1, v2 int) (r1, r2 int) {
if v1 < 0 || v2 < 0 {
return 0, 0
} else {
return v1, v2
}
}
HERE--参数:
- Go有个很棒的特点就是参数列表可以传不定量参数类型。这个我们在数据类型那一篇已经说过了,此处提一下,不再举例了。
- 函数的参数是以值类型传递的,所以总是会进行一次复制操作。
HERE--返回值:
- Go的函数一个很棒的特点就是支持多返回值。
如(清单1.2)所示,我们有两个返回值r1、r2,那么我们在返回值的时候,也可以先给r1、r2赋值,然后再只写一条return语句,而不是非要把返回值写在return语句后面。如:
(清单1.3)
func hey(v1, v2 int) (r1, r2 int) {
if v1 < 0 || v2 < 0 {
return 0, 0
} else {
r1, r2 = v1, v2 // 给返回值变量赋值
return // 然后只写一条return语句
}
}
二、函数的调用
函数的调用非常简单,只要导入函数所在的包,然后“包.函数”就可以调用了。
但是需要注意一下函数的可见性:如果一个函数的函数名是大写开头的,那这个函数就是包外可见的,如果是小写开头的,那这个函数就包内私有的。
三、匿名函数、闭包
匿名函数是指没有名字的函数,我们暂时把匿名函数和闭包看成是一个东西。
OC的block相当于这里的匿名函数或说闭包。
匿名函数的定义和普通函数定义一样,只是没有名字而已。
匿名函数的调用是在函数结尾加一个参数列表就表示匿名函数的调用。如:
(清单3.1)
func main() {
func(v1, v2 int) {
fmt.Println(v1 + v2)
}(1, 2) // 匿名函数花括号后面直接跟参数列表表示匿名函数的调用
}
我们知道OC里block只能直接修改全局变量,局部变量在其内部是不能直接修改的,而Go里的匿名函数是可以在其内部直接修改全局变量和局部变量的。
(清单3.2)
var v1 = 11 // 全局变量:注意全局变量只能用这种方式定义
func main() {
v2 := 12 // 局部变量
func() {
v3 := 13 // 局部变量
v1 = 22
v2 = 24
v3 = 26
fmt.Println(v1, v2, v3)
}() // 匿名函数花括号后面直接跟参数列表表示匿名函数的调用
}
四、函数作为值传递
在Go语言里,函数和其它东西一样,也是一个值而已,因此它是可以作为值赋值给变量。
函数作为值赋值给变量:
(清单4.1)
func main() {
a := func() {
v1 := 11
v2 := 12
fmt.Println(v1, v2)
}
fmt.Printf("%T", a) // 打印a的类型为func()
a() // 调用a
}
函数作为参数传递并作为回调:
(清单4.2)
func main() {
// 调用myFunc1,并把myFunc函数传进去
myFunc1(myFunc)
}
// 这个函数的标识为 func(int)
func myFunc(v int) {
fmt.Println(v) // 该函数的功能是打印
}
func myFunc1(f func(int)) { // 把这个函数作为参数
f(11) // 此处调用这个函数,就会去回调myFunc打印了
}
五、错误处理
1、error
Go语言提供了一个error接口,即:
(清单1.1)
type error interface {
Error() string
}
那么在我们的开发中,对于大多数函数,如果要返回错误,大致上都可以定义为如下模式,将error作为多种返回值中的最后一个(但这并非是强制要求):
(清单1.2)
func myFunc(param int) (n int, err error) {
// 函数体
}
调用时的代码建议按如下方式处理错误情况:
(清单1.3)
n, err := myFunc(0)
if err != nil {
// 错误处理
} else {
// 使用返回值n
}
关于自定义error,后面如果需要可继续学习。
2、延迟执行defer关键字(当defer所处的函数退出前会调用defer关键字后面的函数)
defer关键字用来推迟执行一些函数,如关闭文件句柄、做一些复杂的清理工作等。
defer关键字后面跟着的函数,会在defer所处的函数退出前调用。
一个函数中可以有多个defer语句,那么这多个defer语句的执行顺序为先进后出。
(清单2.1)
func main() {
for i := 0; i < 5; i++ {
defer fmt.Println(i) // 然后等main函数退出时,打印i,因为多个defer语句为前进后出的执行,所以会打印4,3,2,1,0
}
fmt.Println("你好")// 会先打印,你好
}
3、Panic(恐慌)和Recover(恢复)
这个是Go语言的异常处理机制,类似我们OC抛出异常,我们应当把这种手段作为最后的手段被使用,代码中应该没有或尽量少地出现令人恐慌的东西。
如果需要,后面学习。