昨天介紹到參數不定函式,今天立馬來繼續學習匿名函式~
目前為止我們的函式都是必須在套件層級宣告的 具名函式:
func myFavorite() { // myFavorite 便是此函式的名稱
// 執行的程式碼
}
但其實也有另一種 匿名函式(anonymous functions) ,顧名思義是沒有名稱的函式。
以下使用範例 1 試著在 main 函式裡宣告匿名函式:
範例 1:
package main
import "fmt"
func main() {
func() { // 在 main 裡宣告匿名函式
fmt.Println("奇犽")
}() // 用 () 立即呼叫這個匿名函式
}
範例 1(執行結果):
奇犽
若有需要傳給匿名函式的引數,可以將引數寫在最後的小括弧中,如範例 2:
範例 2:
package main
import "fmt"
func main() {
myFavorite := "奇犽"
func (str string) {
fmt.Println(str)
}(myFavorite) // 傳給函式的引數寫在 () 小括號內
}
範例 2(執行結果):
奇犽
範例 1.2 我們都是使用 () 小括號來立即執行匿名函式,但也可以將函式存在變數中,通過變數來呼叫匿名函式:
範例 3:
package main
import "fmt"
func main() {
f := func() {
fmt.Println("變數裡的匿名函式")
}
fmt.Println("我是本來 main 函式裡要印出的字") // func 是逐行執行,所以會先印出這句
f() // 在此行才通過變數呼叫匿名函式,這時控制權才轉向上方的匿名函式,進而印出函式內的字
}
範例 3(執行結果):
我是本來 main 函式裡要印出的字
變數裡的匿名函式
閉包(closure) 是匿名函式的形式之一,一般來說,函式在離開範圍後便無法引用父函式的區域變數,但是閉包便有辦法:
範例 4:
package main
import "fmt"
func main() {
add := addFunc() // 接收傳回的 addFunc 函式
fmt.Println(add())
fmt.Println(add())
fmt.Println(add())
}
func addFunc() func() int {
i := 0 // 定義 i 為匿名函式的父函式內的變數
return func() int { // 回傳一個匿名函式
i++
return i
}
}
範例 4(執行結果):
1
2
3
範例 4 我們呼叫 add() 函式會發現他每次印出的值都有加一,代表他有記得 i 的值,這個我們稱為閉包,也可以稱為 語意閉包(lexical closure) ,閉包即使離開父函式執行範圍,也有能夠記住父函式變數的特性。
在 Go 語言中,函式跟字串一樣也是一種型別,因為是一種型別,代表我們可以將函式當作引數、回傳值,或是像範例 4 一樣拿函式賦值給變數。
若想把函式當成引數,就應該要明確指明接收參數型別,而函式型別定義就是我們前幾天有介紹到的 參數 跟 傳回值型別 ,若想要更好辨識或是閱讀,我們可以使用 自訂函式型別 。
type myFavorite func() // 自訂一個名為 myFavorite 的函式型別,但不需要輸入參數也沒有傳回值
type myFavorite func(string) string // 自訂一個名為 myFavorite 的函式型別,接收一個字串參數,以及傳回一個字串型別的值
今天介紹了匿名函式與閉包,那明天我們繼續了解函式的最後一部份 defer ,明天見~~~