十一、Go基礎程式設計:遞迴函式、函式型別、匿名函式與閉包
阿新 • • 發佈:2018-10-31
1. 遞迴函式
遞迴指函式可以直接或間接的呼叫自身。
遞迴函式通常有相同的結構:一個跳出條件和一個遞迴體。所謂跳出條件就是根據傳入的引數判斷是否需要停止遞迴,而遞迴體則是函式自身所做的一些處理。
//通過迴圈實現1+2+3……+100 func Test01() int { i := 1 sum := 0 for i = 1; i <= 100; i++ { sum += i } return sum } //通過遞迴實現1+2+3……+100 func Test02(num int) int { if num == 1 { return 1 } return num + Test02(num-1) //函式呼叫本身 } //通過遞迴實現1+2+3……+100 func Test03(num int) int { if num == 100 { return 100 } return num + Test03(num+1) //函式呼叫本身 } func main() { fmt.Println(Test01()) //5050 fmt.Println(Test02(100)) //5050 fmt.Println(Test03(1)) //5050 }
2. 函式型別
在Go語言中,函式也是一種資料型別,我們可以通過type來定義它,它的型別就是所有擁有相同的引數,相同的返回值的一種型別。
type FuncType func(int, int) int //宣告一個函式型別, func後面沒有函式名 //函式中有一個引數型別為函式型別:f FuncType func Calc(a, b int, f FuncType) (result int) { result = f(a, b) //通過呼叫f()實現任務 return } func Add(a, b int) int { return a + b } func Minus(a, b int) int { return a - b } func main() { //函式呼叫,第三個引數為函式名字,此函式的引數,返回值必須和FuncType型別一致 result := Calc(1, 1, Add) fmt.Println(result) //2 var f FuncType = Minus fmt.Println("result = ", f(10, 2)) //result = 8 }
3. 匿名函式與閉包
所謂閉包就是一個函式“捕獲”了和它在同一作用域的其它常量和變數。這就意味著當閉包被呼叫的時候,不管在程式什麼地方呼叫,閉包能夠使用這些常量或者變數。它不關心這些捕獲了的變數和常量是否已經超出了作用域,所以只有閉包還在使用它,這些變數就還會存在。
在Go語言裡,所有的匿名函式(Go語言規範中稱之為函式字面量)都是閉包。匿名函式是指不需要定義函式名的一種函式實現方式,它並不是一個新概念,最早可以回溯到1958年的Lisp語言。
func main() { i := 0 str := "mike" //方式1 f1 := func() { //匿名函式,無參無返回值 //引用到函式外的變數 fmt.Printf("方式1:i = %d, str = %s\n", i, str) } f1() //函式呼叫 //方式1的另一種方式 type FuncType func() //宣告函式型別, 無參無返回值 var f2 FuncType = f1 f2() //函式呼叫 //方式2 var f3 FuncType = func() { fmt.Printf("方式2:i = %d, str = %s\n", i, str) } f3() //函式呼叫 //方式3 func() { //匿名函式,無參無返回值 fmt.Printf("方式3:i = %d, str = %s\n", i, str) }() //別忘了後面的(), ()的作用是,此處直接呼叫此匿名函式 //方式4, 匿名函式,有參有返回值 v := func(a, b int) (result int) { result = a + b return }(1, 1) //別忘了後面的(1, 1), (1, 1)的作用是,此處直接呼叫此匿名函式, 並傳參 fmt.Println("v = ", v) }
閉包捕獲外部變數特點:
func main() {
i := 10
str := "mike"
func() {
i = 100
str = "go"
//內部:i = 100, str = go
fmt.Printf("內部:i = %d, str = %s\n", i, str)
}() //別忘了後面的(), ()的作用是,此處直接呼叫此匿名函式
//外部:i = 100, str = go
fmt.Printf("外部:i = %d, str = %s\n", i, str)
}
函式返回值為匿名函式:
// squares返回一個匿名函式,func() int
// 該匿名函式每次被呼叫時都會返回下一個數的平方。
func squares() func() int {
var x int
return func() int {//匿名函式
x++ //捕獲外部變數
return x * x
}
}
func main() {
f := squares()
fmt.Println(f()) // "1"
fmt.Println(f()) // "4"
fmt.Println(f()) // "9"
fmt.Println(f()) // "16"
}
函式squares返回另一個型別為 func() int 的函式。對squares的一次呼叫會生成一個區域性變數x並返回一個匿名函式。每次呼叫時匿名函式時,該函式都會先使x的值加1,再返回x的平方。第二次呼叫squares時,會生成第二個x變數,並返回一個新的匿名函式。新匿名函式操作的是第二個x變數。