函数
func 函数名 (形参列表) (返回值列表) { 函数体 }
在函数中,实参通过值传递的方式进行传递,因此函数的形参是实参的拷贝,对形参进行修改不会影响实参,但是,如果实参包括引用类型,如指针、slice(切片)、map、function、channel 等类型,实参可能会由于函数的间接引用被修改。
Go语言支持多返回值,多返回值能方便地获得函数执行后的多个返回参数,Go语言经常使用多返回值中的最后一个返回参数返回函数执行中可能发生的错误
函数变量
把函数作为值保存到变量中
在Go语言中,函数也是一种类型func(),可以和其他类型一样保存在变量中
func main() {
var f func()
f = fire
f()
}
func fire() {
fmt.Println("fffffffff")
}
init函数
每个源文件都可以包含一个init函数,会在main方法执行前,被Go运行框架调用
- 如果一个文件中同时包含全局变量定义,init函数和main函数,执行顺序是变量定义 –》init函数 –》main
匿名函数
匿名函数的定义就是没有名字的普通函数定义。如果我们只想在一个地方调用这个函数,可以定义匿名函数
func main() {
func(data int) {
fmt.Println(data)
}(100) // 这里表示对匿名函数的调用,传递参数为100
}
匿名函数的用途非常广泛,它本身就是一种值,可以方便地保存在各种容器中实现回调函数和操作封装。
func main() {
sl := make([]int, 3, 6)
sl[0] = 99
sl[1] = 9
sl[2] = 8
visit(sl, func(i int) {
fmt.Println(i)
})
}
func visit(list []int, f func(int)) {
for _, v := range list {
f(v)
}
}
闭包
就是一个函数和与其相关的引用环境组合的一个整体
func AddUpper() func(x int) int {
/*var n = 10
return func(x int) int {
n += x
return n
}*/
}
func main() {
f := AddUpper()
fmt.Println(f(1)) // 11
fmt.Println(f(2)) // 13
fmt.Println(f(3)) // 16
}
对于上面代码来说注释的部分构成闭包:返回一个匿名函数,但是这个匿名函数引用到函数外的n,所以这个匿名函数就和n形成一个整体,构成闭包
在一个闭包中n只初始化一次,所以反复调用f时,n就累加
闭包的关键就是要搞清楚返回的函数它使用到哪些变量
defer
defer用来声明一个延迟函数,defer语句的外层函数返回之前会执行该延迟函数,多用于文件资源,数据库等连接关闭
defer可以放在函数任意位置,但是调用os.Exit时,defer不会执行
func main() {
defer fmt.Println("A")
fmt.Println("B")
os.Exit(0)
}
可以设置多个defer函数,执行遵循先进后出顺序
panic
-
panic 会引起程序的崩溃,因此 panic 一般用于严重错误。对于大部分漏洞,我们应该使用Go语言提供的错误机制,而不是 panic。
-
Go语言程序在宕机时,会将堆栈和 goroutine 信息输出到控制台
-
当 panic() 触发的宕机发生时,panic() 后面的代码将不会被运行,但是在 panic() 函数前面已经运行过的 defer 语句依然会在宕机发生时发生作用,这个特性可以用来做宕机前的处理
recover
让进入宕机流程中的 goroutine 恢复过来,recover 仅在延迟函数 defer 中有效
panic相当于抛出异常,recover相当于对异常进行try/catch处理
func test() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
a := 10
b := 0
res := a / b // go默认有异常panic处理
fmt.Println(res)
}
func main() {
test()
fmt.Println("接着执行。。。")
}
- 有 panic 也有 recover,程序不会宕机,执行完对应的 defer 后,从宕机点退出当前函数后继续执行。
自定义错误
go也支持自定义错误,使用errors.New()和panic函数
errors.New()会返回一个error类型的值,表示一个错误- panic函数接收一个interface{}类型的值,可以接收error类型变量,输出错误信息,退出程序
测试
// 单元测试 go test -v
func TestXxx(t *testing.T) {
要测试的内容
}
// 性能测试 go test -bench="."
func BenchMarkXxx(t *testing.B){
测试内容
}
// 覆盖率测试 go test -cover
执行测试的文件名称必须是_test.go结尾