Go 指针、defer、匿名函数
1. Go 指针
- The * and & operator
- In Go a pointer is represented using the * (asterisk) character followed by the type of the stored value
- * is also used to "dereference" pointer variables
package main import "fmt" type number int func main() { var m number var n *number // 定义 n 为指针类型 m = 1 n = &m // 指针 n 赋值 fmt.Println(m) fmt.Println(n) // 输出地址 fmt.Println(*n) // 输出为 1 }
2. Go defer 表达式
A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns. Defer is commonly used to simplify functions that perform various clean-up actions.
defer 语句会存放在一个列表中,在其它函数语句执行 return 之后再执行。
Deferred function calls are pushed onto a stack. When a function returns, its deferred calls are executed in last-in-first-out order.
defer 语句的执行顺序类似栈的概念, 后进先出 。
package main import "fmt" func main() { fmt.Println("counting") for i := 0; i < 10; i++ { defer fmt.Println(i) // 输出结果是 9, 8, 7, ..., 0 } fmt.Println("done") }
3. 匿名函数
Go 不能在函数内部显式嵌套定义函数,但是可以定义一个匿名函数,Go 通过匿名函数实现闭包(闭包,通过"捕获"自由变量的绑定对函数文本执行的"闭合"操作)。
package main import "fmt" func f(i int) func() int { return func() int { i++ return i } } func main() { m1 := f(2) fmt.Println(m1()) // 指针指向 i, i = 2, 输出 3 fmt.Println(m1()) // 指针指向 i, i = 3, 输出 4 m2 := f(2) fmt.Println(m2()) // 指针指向 另外一个 i,i = 2,输出 3 }
4. 实例
前段时间在 twitter 看到一个例子,问以下代码应该输出什么,后来分析之后才知道结果,代码如下:
package main import "fmt" type number int func (n number) print() { fmt.Printf("输出 number 值 print: %v\n", n) } func (n *number) pprint() { fmt.Printf("输出 number 值 pprint: %v\n", *n) } func main() { var n number defer n.print() defer n.pprint() defer func() { n.print() }() defer func() { n.pprint() }() n = 3 }
输出结果如下:
➜ ~ go run test.go 输出 number 值 pprint: 3 输出 number 值 print: 3 输出 number 值 pprint: 3 输出 number 值 print: 0
根据 defer 的后进先出原则,4 个 defer 语句的执行顺序为倒序的,最后两个属于闭包,很好的理解输出为 3。 defer n.pprint()
语句因为是指针,所以输出结果依然为 3。 defer n.print()
为何为 0,这个相对较难理解,根据上文的说明, var n number
执行后,n 被初始化为 0,之后 defer 语句就被传入内存的 list 中,因此 defer n.print()
输出值为 0。