Go語言之函式進階
阿新 • • 發佈:2021-11-21
一、init函式
(一)簡介
每一個原始檔都可以包含一個init函式,該函式會在main函式執行前,被Go執行框架呼叫,也就是說init會在main函式前呼叫。
package main import "fmt" // init函式,通常可以在init函式中完成初始化工作 func init() { fmt.Println("init...") } func main() { fmt.Println("main...") } /*
輸出:
init... main... */
(二)單包中變數、init、main中的呼叫
如果一個檔案同時包含全域性變數定義、init函式和main函式,則執行的流程是:全域性變數定義--》init函式--》main函式
package main import "fmt" var age = test() // 通過此函式可以看到是否呼叫變數 func test() int { fmt.Println("test...") return 12 } func init() { fmt.Println("init...") } func main() { fmt.Println("main...") } /* 輸出: test... init... main... */
(三)多包中變數、init、main中的呼叫
多包組織:
- utils.go
package utilsimport "fmt" var Age int // Age 全域性變數,在init函式中進行初始化 func init() { fmt.Println("utils包init...") Age = 20 }
- main.go
package main import ( "fmt" "go_tutorial/day06/initFunc/03/utils" //引入utils包 ) var age = test() func test() int { fmt.Println("test...") return 12 } func init() { fmt.Println("init...") } func main() { fmt.Println("main...") fmt.Println("init...",utils.Age) } /* 輸出 utils包init... test... init... main... init... 20 */
如果main.go和utils.go中如果由變數定義、init函式,那麼執行順序是怎麼樣的呢?
main.go中先引入utils包,所以會執行utils.go中的變數定義、init函式。
二、匿名函式
(一)區域性匿名函式
Go支援匿名函式,匿名函式就是沒有名字的函式。
- 使用方式一
在定義匿名函式時就直接呼叫,這種方式匿名函式只能呼叫一次。
package main import "fmt" func main() { res := func(n1 int, n2 int) int { return n1 + n2 }(5, 10) fmt.Println(res) }
- 使用方式二
將匿名函式賦值給一個變數,然後通過變數的方式進行呼叫。
package main import "fmt" func main() { a := func(n1 int, n2 int) int { return n1 + n2 } res := a(10, 5) fmt.Println(res) }
(二)全域性匿名函式
如果將匿名函式賦值給一個全域性變數,那麼這個匿名函式就成為一個全域性匿名函式。
package main import "fmt" var ( Func = func(n1 int, n2 int) int { return n1 + n2 } ) func main() { // 全域性匿名函式呼叫 res := Func(10, 5) fmt.Println(res) }
三、閉包
閉包就是一個函式與其相關的引用環境組成的一個整體。
package main import "fmt" // 累加器 func AddUpper() func(int) int { var n int = 5 return func(x int) int { n = n + x return n } } func main() { f := AddUpper() fmt.Println(f(1)) fmt.Println(f(2)) } /* 輸出: 6 8 */
AddUper是一個函式,它的返回值是一個匿名函式,這裡匿名函式與變數n組成的就是一個閉包。閉包可以儲存上次引用的n值,而不用反覆傳入。
四、defer
在函式中,程式設計師經常需要建立資源(如:資料庫連線、檔案控制代碼等),為了在函式執行完畢後,及時釋放資源,Go中提供defer延時機制。
package main import "fmt" func sum(n1 int, n2 int) int { // 當執行當defer會被延遲執行,先執行defer後面的語句 // defer的語句會被壓入到棧中,按照先如入後出的方式出棧 // 當sum函式執行完畢後會執行defer defer fmt.Println("sum n1=", n1) // 第三步 defer fmt.Println("sum n2=", n2) // 第二步 res := n1 + n2 fmt.Println("sum res=", res) // 第一步 return res } func main() { res := sum(5, 10) fmt.Println("main res=", res) // 第四步 } /* 輸出: sum res= 15 sum n2= 10 sum n1= 5 main res= 15 */
- 當go執行到一個defer時,不會立即執行defer後的語句,而是將defer後的語句到一個棧中,然後繼續執行函式下一個語句
- 當函式執行完畢後,再從defer棧中,一次從棧頂取出語句執行
- 在defer將語句放入到棧中時,也會將相關的值拷貝同時入棧
defer主要的價值就是當函式執行完畢後可以及時釋放函式建立的資源,如:
package main import "fmt" func test1() { // 關閉檔案資源 f := openfile("filePath") defer f.close() // 操作檔案程式碼 // ... } func test2() { // 關閉資料庫資源 connect := openDatabase("connect path") defer connect.close() // 操作資料庫程式碼 // ... } func main() { }作者:iveBoy 出處:http://www.cnblogs.com/shenjianping/ 本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須在文章頁面給出原文連線,否則保留追究法律責任的權利。