//defer後面必須是函數調用語句或方法調用語句,不能是其餘語句,不然編譯器會出錯。 package main import ( "fmt" ) func foo(n int) int { defer n++ //defer fmt.Println(n) return n } func main() { var i int = 100 foo(i) }
# command-line-arguments expression in defer must be function call syntax error: unexpected ++ at end of statement
defer
語句的用途含有 defer
語句的函數,會在該函數將要返回以前,調用另外一個函數。express
defer後面的函數在defer語句所在的函數執行結束的時候會被調用;小程序
package main import ( "fmt" ) type person struct { firstName string lastName string } func (p person) fullName() { fmt.Printf("%s %s",p.firstName,p.lastName) } func main() { p := person { firstName: "John", lastName: "Smith", } defer p.fullName() fmt.Printf("Welcome ") }
在上面的程序裏的第 11 行,a
的初始值爲 5。在第 12 行執行 defer
語句的時候,因爲 a
等於 5,所以延遲函數 printA
的實參也等於 5。接着咱們在第 13 行將 a
的值修改成 10。下一行會打印出 a
的值。該程序輸出:函數
value of a before deferred function call 10 value of a in deferred function 5
從上面的輸出,咱們能夠看出,在調用了 defer
語句後,雖然咱們將 a
修改成 10,但調用延遲函數 printA(a)
後,仍然打印的是 5。code
當一個函數內屢次調用 defer
時,Go 會把 defer
調用放入到一個棧中,隨後按照後進先出(Last In First Out, LIFO)的順序執行。對象
咱們下面編寫一個小程序,使用 defer
棧,將一個字符串逆序打印。blog
package main import ( "fmt" ) func main() { name := "Naveen" fmt.Printf("Orignal String: %s\n", string(name)) fmt.Printf("Reversed String: ") for _, v := range []rune(name) { defer fmt.Printf("%c", v) }}
Orignal String: Naveen Reversed String: neevaN
func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { return } defer src.Close() dst, err := os.Create(dstName) if err != nil { return } defer dst.Close() // other codes return io.Copy(dst, src) }
在打開輸入文件輸出文件後,無論後面的代碼流程如何影響,這兩個文件可以被自動關閉。 字符串
func foo(...) { mu.Lock() defer mu.Unlock() // code logic }
確保mu鎖可以在函數foo退出以後自動釋放。編譯器
WaitGroup的退出
package main import ( "fmt" "sync" ) type rect struct { length int width int } func (r rect) area(wg *sync.WaitGroup) { defer wg.Done() if r.length < 0 { fmt.Printf("rect %v's length should be greater than zero\n", r) return } if r.width < 0 { fmt.Printf("rect %v's width should be greater than zero\n", r) return } area := r.length * r.width fmt.Printf("rect %v's area %d\n", r, area) } func main() { var wg sync.WaitGroup r1 := rect{-67, 89} r2 := rect{5, -67} r3 := rect{8, 9} rects := []rect{r1, r2, r3} for _, v := range rects { wg.Add(1) go v.area(&wg) } wg.Wait() fmt.Println("All go routines finished executing") }