1.defer修饰的函数的执行顺序
例如:
package main
import "fmt"
func main() {
defer func() {
fmt.Println("world")
}()
defer func() {
fmt.Println("hello")
}()
defer func() {
fmt.Println("110")
}()
}
运行结果:
110
hello
world
defer定义的函数的执行顺序跟栈的结构一样,先进后出的顺序执行对应的函数。实际使用中如果要严格的执行顺序,一定要格外注意。
2.defer的拷贝特性
示例:
package main
import "fmt"
func Show(n int) int {
defer fmt.Println("defer n = ", n)
n++
return n
}
func Modify(str *string) {
*str += " world"
defer fmt.Println(*str)
*str += " wula"
}
func main() {
fmt.Println("Show n = ", Show(1))
ss := "hello"
Modify(&ss)
fmt.Println(ss)
}
运行结果:
[root@localhost go]# go run godefer.go
defer n = 1
Show n = 2
hello world
hello world wula
如上代码所示,按照defer关键字,在函数返回的时候才执行,按照正常的逻辑n应该为2,为什么结果等于1呢?是因为defer 函数,的时候,除了将对应的函数放到执行栈中,还将对应的使用的值进行了一份拷贝。等到执行时候,直接就输出了存放函数栈时的值。
3. defer跟return的返回关联
package main
import "fmt"
// 匿名返回
func Kan() int {
var i int
defer func() {
i++
fmt.Println("Kan >>>", i)
}()
defer func() {
i++
fmt.Println("Kan <<<", i)
}()
return i // 匿名返回函数该处底层会创建一个副本进行返回,类似t = i,在return之前执行defer函数,但是此时return处的值已经为t,在defer执行完之后,返回的就是t
}
// 命名返回
func Jan() (i int) {
defer func() {
i++
fmt.Println("Jan >>>", i)
}()
defer func() {
i++
fmt.Println("Jan <<<", i)
}()
return i // 命名返回该处不会创建副本,仍旧i本身,实际在return之前,就已经调用了defer函数,从而导致i的值被修改了,故此可称为defer修改命名返回函数的值
}
func main() {
fmt.Println(Kan())
fmt.Println(Jan())
}
运行结果:
[root@localhost go]# go run godefer.go
Kan <<< 1
Kan >>> 2
0
Jan <<< 1
Jan >>> 2
2