1. 程式人生 > 其它 >Go語言之函式進階

Go語言之函式進階

一、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 utils

import "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/ 本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須在文章頁面給出原文連線,否則保留追究法律責任的權利。