Functions(函式)
介紹
函式是執行某項作業的程式碼區塊。 函式可以選擇性地定義輸入參數,以讓呼叫端將引數傳遞給函式。 函式可以選擇性地傳回值做為輸出。函式適用於將一般作業封裝在單一可重複使用的區塊中,而且其名稱最好可清楚描述該函式的作用。
主函式main當程式執行時,就會去執行此函式。
func main() {
fmt.Print("Hello world!!")
}
動手寫函式
除了主函式之外也可以自行寫函式:
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)
}
也可以先宣告要回傳的變數名稱,最後直接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
}
也可以傳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
}
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
}
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
}
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()
}
func f() (result int) {
result = 10
defer func() {
result++
}()
return
}
func main() {
fmt.Println(f()) //11
}
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") //不會執行
}