GO学习笔记(7)
七. 函数
GO语言的函数特点:
1. 不需要声明原型
2. 支持可变参数
3. 支持多返回值
4. 支持匿名函数和闭包
5. 不支持嵌套
6. 一个包不能有同名函数
7. 不支持重载
8. 不支持默认参数
这里重点记录可变参,闭包和延迟调用
7.1. 可变参
// 固定类型的不定参数 func func1(arg ...int) { fmt.Println(arg) } // 任意类型的不定参数 func func2(arg ...interface{}) { fmt.Println(arg) } func main() { func1(1, 2, 3) a := []int{1, 2, 3, 4} func1(a...) // 必须展开 //func1("qwe") // 报错: cannot use "qwe" (type untyped string) as type int in argument to func1 func2(1, 2) func2(a) // [[1 2 3 4]] func2("qwe") }
7.2. 闭包 (和nodejs闭包类似)
func closure() func() { i := 0 x := func() { i++ fmt.Println(i) } return x } func main() { a := closure() a() // 1 a() // 2 a() // 3 a() // 4 closure() // 没有输出 }
7.3 延迟调用
// 1. 基本用法
func deferDemo() { // 关键字 defer a := [5]int{} for i := range a{ fmt.Println("i = ", i) defer fmt.Println("defer i = ",i) } for i := range a { defer func() {fmt.Println("closure i = ",i)}() } /** 输出: i = 0 i = 1 i = 2 i = 3 i = 4 closure i = 4 closure i = 4 closure i = 4 closure i = 4 closure i = 4 defer i = 4 defer i = 3 defer i = 2 defer i = 1 defer i = 0 第一次循环里 就使用了defer延迟, 所以最先输出的是 i=xxx; 多个defer语句,按先进后出的方式执行, defer的调用顺序是 defer i=0,1,2,3,4,closure i = 4, 所以先输出closure i = 4 因为第二个循环里使用了闭包, 由于闭包中的i在执行的时候已经是4, 所以输出全部是4 */ } // 2. 易错点 type Test struct { name string } func (t *Test)close1() { //fmt.Println("close1:",t.name) fmt.Printf("close1: %p, %v \n", &t, t.name) } func (t Test)close2() { fmt.Printf("close2: %p, %v \n", &t, t.name) //fmt.Println("close2:", t.name) } func deferDemo2() { ts := []Test{{"a"}, {"b"}, {"c"}} for _, t := range ts { fmt.Printf("deferDemo2:close1: %p \n",&t) defer t.close1() // 传递的是引用类型 } for _, t := range ts { fmt.Printf("deferDemo2:close2: %v \n",t) defer t.close2() // 传递值类型 } /** deferDemo2:close1: 0xc000088230 deferDemo2:close1: 0xc000088230 deferDemo2:close1: 0xc000088230 deferDemo2:close2: {a} deferDemo2:close2: {b} deferDemo2:close2: {c} close2: 0xc000088270, c close2: 0xc000088290, b close2: 0xc0000882b0, a close1: 0xc0000cc020, c close1: 0xc0000cc028, c close1: 0xc0000cc030, c defer后面的语句在执行的时候,函数调用的参数会被保存起来,但是不执行。也就是复制了一份。 close1因为参数是是t的地址, 虽然是复制了三次,但是t的地址是相同的 */ }
// 3. 延迟调用发生错误, 这些调用依然会执行
func deferDemo3(x int) {
defer fmt.Println("a")
defer fmt.Println("b")
defer func() {
fmt.Println(100 / x) // 参数为0, 发生异常
}()
defer fmt.Println("c")
}
func main() {
deferDemo3(1) // c 100 b a
deferDemo3(0) // c b a panic: runtime error: integer divide by zero
}