转: https://www.jianshu.com/p/5b0b36f398a2
------------------------------------------------------------
go语言defer语句的用法
defer后面必须是函数调用语句,不能是其他语句,否则编译器会出错。
package main import "log" func foo(n int) int { defer n++ //defer log.Println("n=", n) return n } func main() { var i int = 100 foo(i) }这个例子中defer后面使用的是n++指令,不是一个函数调用语句,编译器就报错:
# command-line-arguments ./main.go:6: expression in defer must be function call ./main.go:6: syntax error: unexpected ++ at end of statementdefer后面的函数在defer语句所在的函数执行结束的时候会被调用;我们查看一下汇编吗,看看defer是在什么时候被执行的: 定义两个函数foo1和foo2,功能和代码都是一样,只是其中一个包含defer语句,另一个没有。
func foo1(i int) int { i = 100 i = 200 return i } func foo2(i int) int { i = 100 defer foo() i = 200 return i }这是foo1的汇编代码:
func foo1(i int) int { 44d660: 48 c7 44 24 10 00 00 movq $0x0,0x10(%rsp) 44d667: 00 00 i = 100 44d669: 48 c7 44 24 08 64 00 movq $0x64,0x8(%rsp) 44d670: 00 00 i = 200 44d672: 48 c7 44 24 08 c8 00 movq $0xc8,0x8(%rsp) 44d679: 00 00 return i 44d67b: 48 c7 44 24 10 c8 00 movq $0xc8,0x10(%rsp) 44d682: 00 00 44d684: c3 retq ... }再看foo2的汇编代码:
func foo2(i int) int { 44d690: 64 48 8b 0c 25 f8 ff mov %fs:0xfffffffffffffff8,%rcx 44d697: ff ff 44d699: 48 3b 61 10 cmp 0x10(%rcx),%rsp 44d69d: 76 70 jbe 44d70f <main.foo2+0x7f> 44d69f: 48 83 ec 18 sub $0x18,%rsp 44d6a3: 48 89 6c 24 10 mov %rbp,0x10(%rsp) 44d6a8: 48 8d 6c 24 10 lea 0x10(%rsp),%rbp 44d6ad: 48 c7 44 24 28 00 00 movq $0x0,0x28(%rsp) 44d6b4: 00 00 i = 100 44d6b6: 48 c7 44 24 20 64 00 movq $0x64,0x20(%rsp) 44d6bd: 00 00 defer foo() 44d6bf: c7 04 24 00 00 00 00 movl $0x0,(%rsp) 44d6c6: 48 8d 05 93 fb 01 00 lea 0x1fb93(%rip),%rax # 46d260 <go.func.*+0x41> 44d6cd: 48 89 44 24 08 mov %rax,0x8(%rsp) 44d6d2: e8 e9 3e fd ff callq 4215c0 <runtime.deferproc> 44d6d7: 85 c0 test