Go語言中的defer
語句會將其後面跟隨的語句進行延遲處理。在defer
歸屬的函數即將返回時,將延遲處理的語句按defer
定義的逆序進行執行,也就是說,先被defer
的語句最後執行,最後被defer
的語句,最早被執行。git
func main() { fmt.Println("start") defer fmt.Print(1) defer fmt.Print(2) defer fmt.Print(3) fmt.Println("end") } // 結果:start end 3 2 1
因爲defer
語句延遲調用的特性,因此defer
語句能很是方便的處理資源釋放問題。。好比:資源清理、文件關閉、解鎖及記錄時間等。github
在Go語言的函數中return
語句在底層並非院子操做,它分爲給返回值賦值和RET指令兩步。而defer
語句執行的實際就在返回值賦值操做後,RET指令執行前。具體以下圖所示:
函數
func f1() int { x := 5 defer func() { x++ }() return x } func f2() (x int) { defer func() { x++ }() return 5 } func f3() (y int) { x := 5 defer func() { x++ }() return x } func f4() (x int) { defer func(x int) { x++ }(x) return 5 } func main() { fmt.Println(f1()) // 5 fmt.Println(f2()) // 6(x等於5,返回值等於x,因此x++後返回值會改變) fmt.Println(f3()) // 5 fmt.Println(f4()) // 5 }
包(package)
是多個Go源碼的集合,是一種高級的代碼複用方案,Go語言爲咱們提供了不少內置包,如fmt
、os
,io
等。code
咱們還能夠根據本身的須要建立本身的包。一個包能夠簡單理解爲一個存放.go
文件的文件夾。該文件夾下面的全部go文件都要在代碼的第一行添加以下代碼,聲明該文件歸屬的包。blog
package 包名
注意事項資源
-
符號。若是想在一個包中引用另一個包裏的標識符(如變量、常量、類型、函數等)時,該標識符必須是對外可見的。在Go語言中只須要將標識符的首字母大寫就可讓標識符對外可見了。編譯器
package main import "fmt" var a = 100 // 首字母小寫,外部包不可見,只能在當前包內使用 // 首字母大寫外部包可見,可在其餘包中使用 const Mode = 1 type person struct { // 首字母小寫,外部包不可見,只能在當前包內使用 name string }
要在代碼中引用其餘包的內容,須要使用import
關鍵字導入使用的包。具體語法以下:源碼
import "包的路徑"
** 注意事項string
$GOPATH/src/
後開始計算的,使用/
進行路徑分隔。單行導入的格式以下:it
import "包1" import "包2"
import (
"包1"
"包2"
)
在導入包名的時候,咱們還能夠爲導入的包設置別名。具體語法格式以下:
import 別名 "包的路徑"
單行導入方式定義別名:
import "fmt" import m "github.com/aaa/bbb/ccc"
多行導入方式定義別名:
import ( "fmt" m "github.com/aaa/bbb/ccc" )
若是隻但願導入包,而不使用包內部的數據時,可使用匿名導入包。具體的格式以下:
import _ "包的路徑"
在Go語言程序執行時導入包語句會自動觸發包內部init()
函數的調用。須要注意的是:init()
函數沒有參數也沒有返回值。init()
函數在程序運行時自動被調用執行,不能在代碼中主動調用它。
包初始化執行的順序以下圖所示:
Go語言包會從main
包開始檢查其導入的全部包,每一個包中又可能導入了其餘的包。Go編譯器由此構建出一個樹狀的包引用關係,再根據引用順序決定編譯順序,依次編譯這些包的代碼。
在運行時,被最後導入的包會最早初始化並調用其init()
函數,以下圖所示: