Functions(函式)

介紹

函式是執行某項作業的程式碼區塊。 函式可以選擇性地定義輸入參數,以讓呼叫端將引數傳遞給函式。 函式可以選擇性地傳回值做為輸出。函式適用於將一般作業封裝在單一可重複使用的區塊中,而且其名稱最好可清楚描述該函式的作用。

主函式main當程式執行時,就會去執行此函式。

func main() {
    fmt.Print("Hello world!!")
}

See in Playground

動手寫函式

除了主函式之外也可以自行寫函式:

func plus(x int, y int) {
    fmt.Println(x + y)
}

func main() {
    plus(50, 30) //80
}

此範例透過plus function達到加法的目的。 有一點要特別注意,當函式需要回傳值時要先設定好回傳值的屬性,如下所示。

func plus(x int, y int) int { //設定回傳型態為int
    return x + y
}

func main() {
    num := plus(50, 30) //80
}

若要回傳多個值也是可行的。

func f() (int, string) { //設定回傳型態為int, string
    return 5, "hello"
}

func main() {
    x, y := f() //x = 5, y = hello
    fmt.Println(x,y)
}

See in Playground

也可以先宣告要回傳的變數名稱,最後直接return即可。

func test(x int) (value int, message string) {
    value = x * 2
    message = "yoyo"
    return
}
func main() {
    var v, m = test(60)
    fmt.Println(v, m) //120 yoyo
}

See in Playground

也可以傳Slices。

func add(args ...int) int {
    total := 0
    for _, v := range args {
        total += v
    }
    return total
}
func main() {
    numList := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    fmt.Println(add(numList...)) //55
}

See in Playground

Closure(閉包)

閉包(Closure)是擁有閒置變數(Free variable)的運算式。閒置變數真正扮演的角色依當時語彙環境(Lexical environment)而定。支援閉包的程式語言通常具有一級函式(First-class function)。建立函式不等於建立閉包。如果函式的閒置變數與當時語彙環境綁定,該函式才稱為閉包。

func minus() func() int {
    i := int(3)
    return func() (ret int) {
        ret = i
        i--
        return
    }
}
func main() {
    next := minus()
    fmt.Println(next()) // 3
    fmt.Println(next()) // 2
    fmt.Println(next()) // 1
}

See in Playground

Recursion(遞迴)

函數可進行遞迴呼叫(recursive call),也就是說在函數之中可呼叫函數本身。函數在進行遞迴呼叫時,在其所使用的變數被堆積在堆疊區域,每次執行 return敘述,函數在該層呼叫中所使用的變數就從堆疊返回。

func fact(x uint) uint {
    if x == 0 {
        return 1
    }
    return x * fact(x-1)
}

func main() {
    fmt.Println(fact(5)) //120
}

See in Playground

Defer, Panic & Recover

Defer

defer的思想類似於C++中的解構子,不過Go語言中“解構”的不是對象,而是函數,defer就是用來添加函數結束時執行的語句。注意這裡強調的是添加,而不是指定,因為Go中的defer是動態的。

func one() {
    fmt.Println("one")
}
func two() {
    fmt.Println("two")
}
func three() {
    fmt.Println("three")
}
func main() {
    one()
    defer two()
    three()  
}

See in Playground

func f() (result int) {
    result = 10
    defer func() {
        result++
    }()
    return
}
func main() {
    fmt.Println(f()) //11
}

See in Playground

Defer, Panic & Recover

Go中可以拋出一個panic的異常,然後在defer中通過recover捕獲這個異常,然後正常處理。

func main() {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println(err) // 這裡的err就是panic傳入的內容
        }
    }()
    fmt.Println("a")
    panic("c")
    fmt.Println("b") //不會執行
}

See in Playground