go--defer語句、包

defer語句

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

defer執行實際和案例分析

defer執行時機

在Go語言的函數中return語句在底層並非院子操做,它分爲給返回值賦值和RET指令兩步。而defer語句執行的實際就在返回值賦值操做後,RET指令執行前。具體以下圖所示:
函數

defer經典案例

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
}

Go語言的包

包的定義

包(package)是多個Go源碼的集合,是一種高級的代碼複用方案,Go語言爲咱們提供了不少內置包,如fmtosio等。code

定義包

咱們還能夠根據本身的須要建立本身的包。一個包能夠簡單理解爲一個存放.go文件的文件夾。該文件夾下面的全部go文件都要在代碼的第一行添加以下代碼,聲明該文件歸屬的包。blog

package 包名

注意事項資源

  • 一個文件夾下面只能有一個包,一樣一個包的文件不能在多個文件夾下。
  • 包名能夠不和文件夾的名字同樣,包名不能包含-符號。
  • 包名爲main的包爲應用程序的入口包,編譯不包含main包的源代碼時不會獲得可執行文件。

可見性

若是想在一個包中引用另一個包裏的標識符(如變量、常量、類型、函數等)時,該標識符必須是對外可見的。在Go語言中只須要將標識符的首字母大寫就可讓標識符對外可見了。編譯器

package main

import "fmt"

var a = 100    // 首字母小寫,外部包不可見,只能在當前包內使用

// 首字母大寫外部包可見,可在其餘包中使用
const Mode = 1

type person struct {    // 首字母小寫,外部包不可見,只能在當前包內使用
    name string
}

包的導入

要在代碼中引用其餘包的內容,須要使用import關鍵字導入使用的包。具體語法以下:源碼

import "包的路徑"

** 注意事項string

  • import導入語句一般放在文件開頭包聲明語句的下面。
  • 導入的包名須要使用雙引號包裹起來。
  • 包名是從$GOPATH/src/後開始計算的,使用/進行路徑分隔。
  • Go語言中禁止循環導入包。

單行導入

單行導入的格式以下: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 _ "包的路徑"

init()初始化函數

init()函數介紹

在Go語言程序執行時導入包語句會自動觸發包內部init()函數的調用。須要注意的是:init()函數沒有參數也沒有返回值。init()函數在程序運行時自動被調用執行,不能在代碼中主動調用它。

包初始化執行的順序以下圖所示:

init()函數執行順序

Go語言包會從main包開始檢查其導入的全部包,每一個包中又可能導入了其餘的包。Go編譯器由此構建出一個樹狀的包引用關係,再根據引用順序決定編譯順序,依次編譯這些包的代碼。

在運行時,被最後導入的包會最早初始化並調用其init()函數,以下圖所示:

相關文章
相關標籤/搜索