函数定义
不支持嵌套(nested)、重载(overload)和默认参数(default paramter)。
- 无需声明原型
- 支持不定长变参
- 支持多返回值
- 支持命令返回值
- 支持匿名函数和闭包
函数是第一类对象,可以作为参数传递。
// 定义函数类型
type FormatFuncu func(s string, x,y int) string
// 函数类型作为参数
func format(fn FormatFuncu, s string, x, y int) string {
return fn(s, x, y)
}
不定参数
不定参数本质上就是 slice
,只能有一个,且必须是最后一个。
func test(s string, n ...int) string {
var x int
for _, i := range n {
x += i
}
return fmt.Sprintf(s, x)
}
func main() {
println(test("sum: %d", 1, 2, 3))
}
匿名函数
匿名函数可赋值给变量,做为结构字段,或者在 channel
⾥传送。
闭包复制的是原对象指针。
func test() func() {
x := 100
fmt.Printf("x (%p) = %d\n", &x, x)
return func() {
fmt.Printf("x (%p) = %d\n", &x, x)
}
}
func main() {
f := test()
f()
}
在汇编层⾯,test
实际返回的是 FuncVal
对象,其中包含了匿名函数地址、闭包对象指
针。当调⽤匿名函数时,只需以某个寄存器传递该对象即可。
延迟调用
关键字 defer
⽤于注册延迟调⽤。这些调⽤直到 ret
前才被执⾏,通常⽤于释放资源或错
误处理。
func test() error {
f, err := os.Create("test.txt")
if err != nil { return err }
defer f.Close() // 注册调⽤,⽽不是注册函数。必须提供参数,哪怕为空。
f.WriteString("Hello, World!")
return nil
}
多个 defer
注册,按 FILO
次序执⾏。哪怕函数或某个延迟调⽤发⽣错误,这些调⽤依旧会被执⾏。
延迟调⽤参数在注册时求值或复制,可⽤指针或闭包 "延迟" 读取。
func test() {
x, y := 10, 20
defer func(i int) {
println("defer:", i, y) // y 闭包引⽤
}(x) // x 被复制
x += 10
y += 100
println("x =", x, "y =", y)
}
输出
x = 20 y = 120
defer: 10 120
错误处理
没有结构化异常,使用 panic
抛出错误,recover
捕获错误。
func test() {
defer func() {
if err := recover(); err != nil {
println(err.(string)) // 捕获错误,将 interface{} 转型为具体类型
}
}()
panic("panic error!")
}
因为 panic、recover
参数类型为 interface{}
,因此可以抛出任何类型对象。
func panic(v interface{})
func recover() interface{}
defer
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
defer
将函数放入额外的调用栈,函数调用完成时调用该函数,一般用于释放连接资源。
panic
接收任意参数,抛出错误信息。
出错的时候向上递归返回并调用所有的 defer
释放资源,还能报告错误发生函数的参数,利于定位错误。
recover
捕获抛出的错误,恢复错误流程,一般不推荐使用,出错还是崩了好。