1. 程式人生 > 其它 >詳解Go中匿名函式,閉包函式,回撥函式

詳解Go中匿名函式,閉包函式,回撥函式

技術標籤: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)
	})
}