golang 函數

1、包

go的每個文件都是屬於一個包的,也就是說go是以包的形式來管理文件和項目目錄結構的。數據庫

包的做用

  1. 區分相同名字的函數、變量等標識符
  2. 當程序文件較多,可很好的管理項目
  3. 控制函數、變量等訪問範圍,即做用域

2、函數細節

  • 函數自己也是一種數據類型,能夠賦值給一個變量,該變量就是一個函數類型的變量,經過該變量能夠對函數調用
func getSum(n1 int, n2 int) int {

 return n1 + n2

}

func myFunc(funcvar func(int, int) int, num1 int,num2 int) {

 return funcvar(num1, num2)

}

func main() {

 res := myFunc(getSum, 2, 4)

 fmt.Println("a的類型是%T, getSum 的類型是%T", a, getSum)

}
  • 爲了簡化數據類型定義,go支持自定義數據類型
type myInt int

 var num1 myInt

 var num2 int

 num1 = 40
 num2 = int(num1) // myInt 和int是兩個類型,因此要強轉
  • 支持對函數返回值命名
func getSumAndSub(n1 int, n2 int) (sum int, sub int) {

 sum = n1 + n2

 sub = n1 - n2

 return     // 好處是不用管返回的順序,接收按順序接收就行

}

3、init函數

每個源文件均可以有一個init函數,該函數會在main函數執行前,被Go框架調用。
若是一個文件包含全局變量定義,init函數和main函數,則執行流程是 變量定義>init函數>main函數,若是main.go 引入了包,則執行流程是 包的變量定義>包的init函數>main的變量定義>main的init函數>main的main函數閉包

func init() {

 fmt.Println("init()...")

}

func main() {

 fmt.Println("main()...")

}

3、匿名函數

若是但願函數只使用一次,能夠考慮匿名函數,匿名函數也可實現屢次調用。框架

var (
// 全局匿名函數
 Func1 := func (n1 int, n2 int) int {

 return n1 + n2

 }

)

func main() {

 // 在定義匿名函數時直接調用, 這種方式匿名函數只能調用一次

 result := func (n1 int, n2 int) int {

 return n1 + n2

 }(n1, n2)

 // 將匿名函數func (n1 int, n2 int) int 賦值給a變量,則a的數據類型就是函數類型,此時可經過a進行調用

 a := func (n1 int, n2 int) int {

 return n1 + n2

 }

 res := a(10, 20)

 fmt.Println("main()...")

}

3、閉包

一個函數和其相關的引用環境組合的一個總體(實體)函數

func AddUpper() func (int) int {

 var n int = 10;

 return func (x int) int {

 n = n + x

 return n

 }

}

func main() {

 f := AddUpper()

 fmt.Println(f(1)) // 11

 fmt.Println(f(2)) // 13

}

上面代碼說明:spa

  1. AddUpper是個函數,返回的數據類型是func(int) int
  2. image.png

返回的是一個匿名函數,但這個匿名函數引用到函數外的n,所以這個匿名函數就和n造成一個總體,構成閉包設計

  1. 能夠理解閉包是一個類,函數是操做,n是字段,函數和它使用到的n構成閉包
  2. 當咱們反覆調用f函數時,由於n只初始化一次,所以每調用一次就進行累計
  3. 要搞清楚閉包的關鍵,就是要分析出返回的函數它使用(引用)到哪些變量,由於函數和它引用到的變量共同構成閉包

4、函數中的defer

在函數中,常常要建立資源(數據庫鏈接、文件句柄、鎖等),爲了在函數執行完畢後,及時釋放資源。Go的設計者提供defer(延時機制)code

func sum (n1 int, n2 int) int {

 // 當執行到defer時,暫時不執行,會將defer後面的語句壓入到獨立的棧(defer棧)

 // 當函數執行完畢後,再從defer棧,按照先入後出的方式出棧,執行

 defer fmt.Println("n1 = ", n1)

 defer fmt.Println("n2 = ", n2)

 return n1 + n2

}

func main() {

 res := sum(10, 20)

 fmt.Printf("%T, %T", f, a) // 151

}

5、函數的參數傳遞

  1. 值類型:默認值傳遞,變量直接存儲值,內存一般在棧中分配
  2. 引用類型:默認引用傳遞,變量存儲的是一個地址,這個地址對應的空間才真正存儲數據,內存一般在堆上分配,當沒有任何變量引用這個地址時,該地址對應的數據空間就成爲一個垃圾由GC回收

6、錯誤處理

Go中引入處理方式是defer,panic,recover
Go中能夠拋出一個panic的異常,而後在defer中經過recover捕獲這個異常,而後正常處理blog

func test () {

 defer func() {

 err := recover() // 內置函數,能夠捕獲到異常

 if err != nil { // 捕獲到錯誤

 fmt.Println("err=", err)

 }

 }()

 num1 := 10

 num2 := 0

 res := num1 / num2

 fmt.Println("res", res)

}

func main() {

 test()

 fmt.Printf("%T, %T", f, a) // 151

}
相關文章
相關標籤/搜索