Go defer使用

 

defer使用語法

//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 棧

當一個函數內屢次調用 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

  

defer 的實際應用

  • file對象打開後的自動關閉
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)
}

 在打開輸入文件輸出文件後,無論後面的代碼流程如何影響,這兩個文件可以被自動關閉。 字符串

  • mutex對象鎖住後的自動釋放
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")
}
相關文章
相關標籤/搜索