「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」
函数
函数声明
函数由5部分组成:函数名、形参列表、返回列表、和函数体。func
为定义函数的关键字
1 | go复制代码func name(parameters-list) (result-list) { |
形参列表的格式是参数名称+参数类型,相同类型的参数可以写在一起
1 | go复制代码// 这两种个写法等价的 |
返回列表的格式是(返回值名称+返回值类型...)
返回值名称可以省,当函数存在返回列表时,必须显示地已return语句结束
1 | go复制代码// 方式一:返回值名称+类型 |
函数的类型称作函数签名
,由函数的形参列表和返回列表确定,形参和返回值名称不会形象函数类型
1 | go复制代码func add(x, y int) int { return x + y } |
我们可以只定义函数签名,函数实现放在其他地方或其他语言
1 | go复制代码func Sin(x float64) float64 |
函数的形参
形参变量是函数的局部变量。通常情况下,调用函数时实参是按值
传递的,因此函数内修改变量不会改变实参的值。
1 | go复制代码func incr(x int) { |
但是,如果实参是引用类型,比如:指针、slice、map、函数或者通道,那么就有可能
改到实参的值
1 | go复制代码func updateSlice(s []int, index int, val int) { |
函数的递归
递归实现斐波那契数列
1 | go复制代码func fib(n int) int { |
递归的实现使用栈结构来保存当前上下文信息。Go语言的实现使用了可变长的栈,栈的长度可以随着使用增加。
函数多指返回
Go语言支持函数的返回值不止一个,一般情况是一个期望计算得到的结果和一个错误值或者一个表示函数调用是否正确的布尔值。
1 | go复制代码func calculate(expr string) (result float64, err error) { |
函数变量
Go语言中,可以声明函数类型的变量,即函数变量。函数变量之间不能比较,只能和nil
比较。
1 | go复制代码var sum func(int, int) int |
函数变量可以作为参数传递
1 | go复制代码func add1(r rune) rune { return r + 1 } // 将字符的Unicode值加1 |
可以在函数内部声明递归函数
1 | go复制代码func main() { |
变长函数
函数可以支持可变的参数数量,比如:fmt.Printf
就是支持可变的数量。在参数列表最后的类型名称前使用...
表示声明一个边长函数,下面我们来实现一个简易的Sprintf
:
1 | go复制代码func Sprintf(format string, params ...interface{}) string { |
可变长度参数只能声明在最后,并且只能有一个,这样就限制了可变参数只能是一种类型,但是fmt.Printf
可以这样写:
1 | go复制代码fmt.Printf("%d %s", 1, "abc") // 1 abc |
这是因为它将可变长度参数的类型声明生成了interface{}
,将会在后面的章节研究。
延迟函数
在一个函数调用或者方法调用前加上defer
关键字,就声明了这个函数(方法)延迟执行
- 延迟到return语句后执行
- 延迟到函数执行完毕后执行
- 延迟到发生宕机时执行
在一个函数作用域内,可以有声明多次延迟函数,执行的时候是以调用defer
语句顺序的倒序进行。
延迟函数一般用于声明函数正常或异常结束后释放资源。
1 | go复制代码conn, err := Client.GetConn() |
此外,还可以结合闭包
实现对一个函数执行时的监控
1 | go复制代码func clock(msg string) func() { |
函数的宕机和恢复
宕机发生在程序的运行时出现了严重的异常情况,比如:错误的输入、配置或者I/O失败等。此时程序执行会终止,goroutine
中的所有延迟函数会执行,然后程序会异常退出。
一些标准库会对不可能发生
的情况做宕机处理,我们自己也可以同宕机函数 panic
来实现:
1 | go复制代码switch isRight { |
有些情况下,当程序发生宕机,我们也不期望程序退出,比如,当Web服务器遇到处理用户请求时遇到宕机情况,不能直接退出,而是要给用户返回当前遇到的错误:
- 如果是用户查询的记录不存在,应该返回404
- 如果是用户输入的参数有问题,应该返回400
…
我们可以通过在函数的延迟函数中调用recover
函数来终止当前的宕机状态并做一些逻辑处理
1 | go复制代码func RequestHandler(c *Context) (res Response) { |
需要注意的是,要合理评估当前情况是否需要对宕机进行恢复,恢复会有一定风险,比如导致资源泄露或使失败的处理函数处于未定义的状态从而导致其他问题。
本文转载自: 掘金