# Go语言的Defer函数

## Defer的特点

* 确保调用在函数结束时发生
* 参数在defer语句时计算
* defer列表为后进先出

### 确保调用在函数结束时发生

下面的例子中，fmt.Println(1)会比fmt.Println(2)晚执行。

```go
func tryDefer() {
	defer fmt.Println(1)
	fmt.Pintln(2)
	panic("error"）
}
func main() {//
	tryDefer()
}
```

再看一个文件的例子

```go
package main

import (
	"fmt"
	"os"
	"bufio"
	"imooc.com/ccmouse/learngo/lang/functional/fib"
)

func writeFile(filename string) {
	file, err := os.OpenFile(filename,
		os.O_EXCL|os.O_CREATE|os.O_WRONLY, 0666)

	if err != nil {
		if pathError, ok := err.(*os.PathError); !ok {
			panic(err)
		} else {
			fmt.Printf("%s, %s, %s\n",
				pathError.Op,
				pathError.Path,
				pathError.Err)
		}
		return
	}
	defer file.Close()

	writer := bufio.NewWriter(file)
	defer writer.Flush()

	f := fib.Fibonacci()
	for i := 0; i < 20; i++ {
		fmt.Fprintln(writer, f())
	}
}

func main() {
	writeFile("fib.txt")
}

```

### 参数在defer语句时计算 / defer列表为后进先出

关于*参数在defer语句时计算*，可以看这个例子。

```go
package main

import (
	"fmt"
	"os"

	"bufio"

	"imooc.com/ccmouse/learngo/lang/functional/fib"
)

func tryDefer() {
	for i := 0; i < 100; i++ {
		defer fmt.Println(i)
		if i == 30 {
			panic("printed too many")
		}
	}
}

func main() {
	tryDefer()
}
```

得到下面的结果，可以看到defer是从10开始打印的，说明后进先出。

然后程序在10的时候停住了，但是并没有打印10个10，说明参数在defer语句时计算。

```
10
9
8
7
6
5
4
3
2
1
0
panic: printed too many
```

## 何时使用defer

* open/close
* lock/unlock
* printheader/pringfooter
