詳解Go中匿名函式,閉包函式,回撥函式
阿新 • • 發佈:2020-12-21
技術標籤:Go基礎
匿名函式
- 匿名函式沒有函式名,只有函式體,函式可以被作為一種型別被賦值給變數,匿名函式也往往以變數的方式被傳遞。
- 匿名函式經常被用於實現回撥函式、閉包等。
- 定義格式如下:
func(引數列表)(返回引數列表){
//函式體
}
- 方式一:在定義時呼叫匿名函式
func anonymousFunc1() {
func(data int) {
fmt.Println("hello", data)
}(100)
}
這裡的100是匿名函式的引數
- 方式二:將匿名函式賦值給變數
func anonymousFunc2() {
f := func( data string) {
fmt.Println(data)
}
f("heelo")
}
i2 := func(x, y int) int { return x + y }(1,2)
如上,定義一個匿名函式,包含兩個引數x,y
。返回x+y
的結果。後面()
,裡面表示引數,引數是:x=1,y=2
。
當然你也可以先定義匿名函式,不適用,等你需要使用的時候,像呼叫函式一樣傳引數就可以:
func anonymousFunc5() {
var x, y int
x = 1
y = 2
i2 := func(x, y int) int { return x + y }
i3 := i2(x, y)
fmt.Println(i3)
}
兩種函式的區別在於(x,y)
引數在哪裡。
- 方式三:有返回引數的後面必須有
return
func anonymousFunc3() {
aaa := func(data int) int {
return data
}
fmt.Println(aaa(1))
}
閉包函式
在程式碼中,函式若f2被包括在函式f1內部,這時f1內部的所有區域性變數,對f2都是可見的。但反過來就不行,f2的區域性變數對f1是不可見的。這就是:鏈式呼叫
因為fs2可以讀取f1中的區域性變數,所以只要把f2作為返回值,我們就可以在f1外部讀取f2的內部變量了
閉包:定義在函式內部的函式,在本質上,閉包是將函式內部(f2的變數)和函式外部(f1的變數)連線起來的橋樑(在go語言中匿名函式就是閉包)
閉包的實現:確保只要閉包在使用,那麼被閉包引用的變數會一直存在
閉包經常用於回撥函式,當IO操作(例如從網路獲取資料、檔案讀寫)完成的時候,會對獲取的資料進行某些操作,這些操作可以交給函式物件處理。
func test() {
a := 5
b := func()(func()){
c := 10
return func() {
fmt.Printf("a,c: %d,%d \n",a,c)
a *= 3
}
}()
b()
println(a)
}
輸出:
a,c: 5,10
15
解釋一下
匿名函式的返回值是一個匿名函式,return返回的是一個匿名函式,注意沒有加(),所以是用return接收。
然後在最外層加了()
。所以講匿名函式的值給了b
。注意了此時的b
其實是一個函式如下圖所示,所以呼叫的時候是b()
。
嘗試將匿名函式的最外層的()去掉:
func test() {
a := 5
b := func()(func()){
c := 10
return func() {
fmt.Printf("a,c: %d,%d \n",a,c)
a *= 3
}
}
fmt.Printf("列印b()型別為:%T\n列印b()值為%v\n",b(),b())
println(a)
輸出:
列印b()型別為:func()
列印b()值為0x477180
5
}
此時b
的是一個值,型別如下所示:
在試一下b()()列印:
func test() {
a := 5
b := func()(func()){
c := 10
return func() {
fmt.Printf("a,c: %d,%d \n",a,c)
a *= 3
}
}
b()()
println(a)
}
輸出:
a,c: 5,10
15
此b()()
為函式,
注意:a在匿名函式內是可以引用的,但是你如果在匿名函式外引用c,你會發現找不到。並且在閉包內改變了a的值也是會作用到a真實的記憶體地址中的。
回撥函式:
回撥函式就是一個被作為引數傳遞的函式。
package main
import (
"fmt"
)
func main() {
arr :=[]float64{1,2,3,4,5,6}
a :=filterSlice(arr, func(f float64) string {
return fmt.Sprint(f)
})
fmt.Println("a",a)
anonymousFunc()
}
type myFunc1 func(f float64) string
//作為回撥函式
//先遍歷一個切片,對切片進行操作的函式
func filterSlice(arr []float64, f myFunc1) []string {
//定義一個切片型別的字串
var result []string
for _, val := range arr {
result = append(result, f(val))
}
fmt.Println("result",result)
return result
}
//對這個函式進行回撥使用
//1.回撥函式就是一個被作為引數傳遞的函式
//2.函式中有一個引數是函式,這個函式就是回撥函式
func anonymousFunc() {
arr :=[]float64{9,8,7,6,5,4,3,2,1,0}
filterSlice(arr, func(f float64) string {
return fmt.Sprint(f)
})
}