函数声明
函数声明的格式:
|
|
- 如果函数返回一个无名变量或者没有返回值,返回值列表的括号是可以省略的
- 如果一个函数声明不包括返回值列表,那么函数体执行完毕后,不会返回任何值
- 参数
- Go语言没有默认参数值,也没有任何方法可以通过参数名指定形参,因此形参和返回值的变量名对于函数调用者而言没有意义。
- 在函数体中,函数的形参作为局部变量,被初始化为调用者提供的值。函数的形参和有名返回值作为函数最外层的局部变量,被存储在相同的词法块中。
- 实参通过值的方式传递,因此函数的形参是实参的拷贝。对形参进行修改不会影响实参。但是,如果实参包括引用类型,实参可能会由于函数的间接引用被修改。
- 函数签名
- 不定义函数体即可
- 例如:
func Sin(x float64) float //implemented in assembly language
递归
多返回值
func Size(rect image.Rectangle) (width, height int)
bare return
- 函数声明是声明多个返回值,在函数体中return时可以只写return,默认返回声明中的变量
- 使用bare return可以不用在return时再次声明返回值(但这样容易出错)
错误
- 内置的error是接口类型
- 打印error可以获得稍微详细一点的错误信息
- go error设计哲学
- 在Go中,函数运行失败时会返回错误信息,这些错误信息被认为是一种预期的值而非异常(exception)
- 虽然Go有各种异常机制,但这些机制仅被使用在处理那些未被预料到的错误,即bug,而不是那些在健壮程序中应该被避免的程序错误。
- Go使用控制流机制(如if和return)处理错误,这使得编码人员能更多的关注错误处理
函数值
在go中,函数被看作是第一类值(first-class values),函数拥有类型,可以被赋值给其他变量,传递给函数,从函数返回
,例如
|
|
- 函数的零值是nil
- 函数之间不可以比较,不能使用函数作为map的key
匿名函数
- 匿名函数与普通的函数相比,只是少了函数名
- 函数值不可比较的一个原因是匿名函数(考虑这样的情景:在闭包中,匿名函数引用了一个闭包内匿名函数外的变量,这个变量可变)
- 闭包老毛病:延迟绑定或者说变量变化
|
|
可变参数
使用...
|
|
- 可变参数和slice的区别?(我感受不到区别)
|
|
- 如何将一个slice作为参数传递给上面例子中的vals?
sum(slice...)
即可
defer
- 在资源获取的地方使用defer函数处理资源释放
- 利用defer可以在资源释放后实现很多奇奇怪怪的操作
- 注意事项
- 在循环中使用defer,例如在循环中打开文件,并使用defer声明关闭操作,那么需要所有文件打开并操作完成后,才会调用每一个defer语句(容易造成文件描述符用尽)
- 解决方法:循环里调用函数,在函数里进行
defer close()
操作,函数在结束时会立马执行defer操作
- 其他
- 许多文件系统,尤其是NFS,写入文件时发生的错误会被延迟到文件关闭时反馈。如果没有检查文件关闭时的反馈信息,可能会导致数据丢失,而我们还误以为写入操作成功
panic异常
- 当panic异常发生时,程序会中断运行,并立即执行在该goroutine中被延迟的函数(defer 机制)
- 程序崩溃并产生日志,日志信息包括
panic value
和函数调用的堆栈跟踪信息
- 直接调用内置的panic函数也会引发panic异常;panic函数接受任何值作为参数。
- panic一般用于严重错误(go提倡对于大部分漏洞,使用Go提供的错误机制而不是panic)
- runtime包允许程序员输出堆栈信息
|
|
- 在Go的panic机制中,
延迟函数的调用在释放堆栈信息之前
。
recover捕获异常
- 通常我们不应该对panic做出任何处理,但有时候或许我们可以在程序崩溃前做一些操作
- 例如服务器遇到不可预料的问题时,可以在崩溃前关闭连接,如果不关闭,客户端会一直处于等待的状态
- 如果在deferred函数中调用了内置函数recover,并且定义该defer语句的函数发生了panic异常,
recover会使程序从panic中恢复,并返回panic value
。导致panic异常的函数不会继续运行,但能正常返回
。在未发生panic时调用recover,recover会返回nil
。
|
|
- panic的处理方法
- 不推荐的做法
- 不加区分的恢复所有的panic异常,不是可取的做法;作为被广泛遵守的规范,你不应该试图去恢复其他包引起的panic;
- 推荐做法
- 在recover时对panic value进行检查,如果发现panic value是特殊类型,就将这个panic作为error处理,如果不是,则按照正常的panic进行处理
- 其中panic value的value是通过panic(value)抛出的
- 不推荐的做法