最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go基礎(chǔ)教程系列之回調(diào)函數(shù)和閉包詳解

 更新時(shí)間:2022年04月16日 16:30:30   作者:駿馬金龍  
這篇文章主要介紹了Go基礎(chǔ)教程系列之回調(diào)函數(shù)和閉包詳解,需要的朋友可以參考下

Go回調(diào)函數(shù)和閉包

當(dāng)函數(shù)具備以下兩種特性的時(shí)候,就可以稱之為高階函數(shù)(high order functions):

  • 函數(shù)可以作為另一個(gè)函數(shù)的參數(shù)(典型用法是回調(diào)函數(shù))
  • 函數(shù)可以返回另一個(gè)函數(shù),即讓另一個(gè)函數(shù)作為這個(gè)函數(shù)的返回值(典型用法是閉包)

一般來(lái)說(shuō),附帶的還具備一個(gè)特性:函數(shù)可以作為一個(gè)值賦值給變量。

f := func(){...}
f()

由于Go中函數(shù)不能嵌套命名函數(shù),所以函數(shù)返回函數(shù)的時(shí)候,只能返回匿名函數(shù)。

先簡(jiǎn)單介紹下高階函數(shù),然后介紹閉包。

高階函數(shù)示例

例如,將函數(shù)作為另一個(gè)函數(shù)的參數(shù):

package main

import "fmt"

func added(msg string, a func(a, b int) int) {
	fmt.Println(msg, ":", a(33, 44))
}

func main() {
	// 函數(shù)內(nèi)部不能嵌套命名函數(shù)
	// 所以main()中只能定義匿名函數(shù)
	f := func(a, b int) int {
		return a + b
	}
	added("a+b", f)
}

以下示例是函數(shù)返回另一個(gè)函數(shù):

package main

import "fmt"

func added() func(a, b int) int {
	f := func(a, b int) int {
		return a + b
	}
	return f
}

func main() {
	m := added()
	fmt.Println(m(33, 44))
}

回調(diào)函數(shù)(sort.SliceStable)

將函數(shù)B作為另一個(gè)函數(shù)A的參數(shù),可以使得函數(shù)A的通用性更強(qiáng),可以隨意定義函數(shù)B,只要滿足規(guī)則,函數(shù)A都可以去處理,這比較適合于回調(diào)函數(shù)。

在Go的sort包中有一個(gè)很強(qiáng)大的Slice排序工具SliceStable(),它就是將排序函數(shù)作為參數(shù)的:

func SliceStable(slice interface{}, less func(i, j int) bool)

這個(gè)函數(shù)是什么意思呢?給定一個(gè)名為slice的Slice結(jié)構(gòu),使用名為less的函數(shù)去對(duì)這個(gè)slice排序。這個(gè)less函數(shù)的結(jié)構(gòu)為less func(i, j int) bool,其中i和j指定排序依據(jù)。Go中已經(jīng)內(nèi)置好了排序的算法,我們無(wú)需自己去定義排序算法,Go會(huì)自動(dòng)從Slice中每次取兩個(gè)i和j索引對(duì)應(yīng)的元素,然后去回調(diào)排序函數(shù)less。所以我們只需要傳遞升序還是降序、根據(jù)什么排序就可以。

例如:

package main

import (
	"fmt"
	"sort"
)

func main() {
	s1 := []int{112, 22, 52, 32, 12}
    // 定義排序函數(shù)
	less := func(i, j int) bool {
        // 降序排序
		return s1[i] > s1[j]
        // 升序排序:s1[i] < s1[j]
	}
    //
	sort.SliceStable(s1, less)
	fmt.Println(s1)
}

這里的排序函數(shù)就是回調(diào)函數(shù)。每取一次i和j對(duì)應(yīng)的元素,就調(diào)用一次less函數(shù)。

可以將排序函數(shù)直接寫(xiě)在SliceStable()的參數(shù)位置:

sort.SliceStable(s1, func(i, j int) bool {
	return s1[i] > s1[j]
})

還可以更強(qiáng)大更靈活。例如,按照字符大小順序來(lái)比較,而不是按照數(shù)值大小比較:

package main

import (
	"fmt"
	"sort"
	"strconv"
)

func main() {
	s1 := []int{112, 220, 52, 32, 42}
	sort.SliceStable(s1, func(i, j int) bool {
		// 將i和j對(duì)應(yīng)的元素值轉(zhuǎn)換成字符串
		bi := strconv.FormatInt(int64(s1[i]), 10)
		bj := strconv.FormatInt(int64(s1[j]), 10)
		// 按字符順序降序排序
		return bi > bj
	})
	fmt.Println(s1)
}

按照字符串長(zhǎng)度來(lái)比較:

package main

import (
	"fmt"
	"sort"
)

func main() {
	s1 := []string{"hello","malong","gaoxiao"}
	sort.SliceStable(s1, func(i, j int) bool {
		// 按字節(jié)大小順序降序排序
		return len(s1[i]) > len(s1[j])
	})
	fmt.Println(s1)
}

更嚴(yán)格地說(shuō)是按字節(jié)數(shù)比較,因?yàn)閘en()操作字符串時(shí)獲取的是字節(jié)數(shù)而非字符數(shù)。如果要按照字符數(shù)比較,則使用如下代碼:

package main

import (
	"fmt"
	"sort"
)

func main() {
	s1 := []string{"hello","世界","gaoxiao"}
	sort.SliceStable(s1, func(i, j int) bool {
		// 按字節(jié)大小順序降序排序
		return len([]rune(s1[i])) > len([]rune(s1[j]))
	})
	fmt.Println(s1)
}

閉包

函數(shù)A返回函數(shù)B,最典型的用法就是閉包(closure)。

簡(jiǎn)單地說(shuō),閉包就是"一個(gè)函數(shù)+一個(gè)作用域環(huán)境"組成的特殊函數(shù)。這個(gè)函數(shù)可以訪問(wèn)不是它自己內(nèi)部的變量,也就是這個(gè)變量在其它作用域內(nèi),且這個(gè)變量是未賦值的,而是等待我們?nèi)ベx值的。

例如:

package main

import "fmt"

func f(x int) func(int) int{
    g := func(y int) int{
        return x+y
    }
    // 返回閉包
    return g
}

func main() {
    // 將函數(shù)的返回結(jié)果"閉包"賦值給變量a
    a := f(3)
    // 調(diào)用存儲(chǔ)在變量中的閉包函數(shù)
    res := a(5)
    fmt.Println(res)

    // 可以直接調(diào)用閉包
    // 因?yàn)殚]包沒(méi)有賦值給變量,所以它稱為匿名閉包
    fmt.Println(f(3)(5))
}

上面的f()返回的g之所以稱為閉包函數(shù),是因?yàn)樗且粋€(gè)函數(shù),且引用了不在它自己范圍內(nèi)的變量x,這個(gè)變量x是g所在作用域環(huán)境內(nèi)的變量,因?yàn)閤是未知、未賦值的自由變量。

如果x在傳遞給g之前是已經(jīng)賦值的,那么閉包函數(shù)就不應(yīng)該稱為閉包,因?yàn)檫@樣的閉包已經(jīng)失去意義了。

下面這個(gè)g也是閉包函數(shù),但這個(gè)閉包函數(shù)是自定義的,而不是通過(guò)函數(shù)返回函數(shù)得到的。

package main

import "fmt"

func main() {
	// 自由變量x
	var x int
	// 閉包函數(shù)g
	g := func(i int) int {
		return x + i
	}
	x = 5
	// 調(diào)用閉包函數(shù)
	fmt.Println(g(5))
	x = 10
	// 調(diào)用閉包函數(shù)
	fmt.Println(g(3))
}

之所以這里的g也是閉包函數(shù),是因?yàn)間中訪問(wèn)了不屬于自己的變量x,而這個(gè)變量在閉包函數(shù)定義時(shí)是未綁定值的,也就是自由變量。

閉包的作用很明顯,在第一個(gè)閉包例子中,f(3)退出后,它返回的閉包函數(shù)g()仍然記住了原本屬于f()中的x=3。這樣就可以讓很多閉包函數(shù)共享同一個(gè)自由變量x的值

例如,下面的a(3)a(5)a(8)都共享來(lái)自f()的x=3。

a := f(3)
a(3)
a(5)
a(8)

再往外層函數(shù)看,f(3)可以將自由變量x綁定為x=3,自然也可以綁定為x=5x=8等等。

所以,什么時(shí)候使用閉包?一般來(lái)說(shuō),可以將過(guò)程分成兩部分或更多部分都進(jìn)行工廠化的時(shí)候,就適合閉包(實(shí)際上,有些地方直接將閉包稱呼為工廠函數(shù))。第一個(gè)部分是可以給自由變量批量綁定不同的值,第二部分是多個(gè)閉包函數(shù)可以共享第一步綁定后的自由變量。

更多關(guān)于Go回調(diào)函數(shù)說(shuō)明,Go閉包說(shuō)明請(qǐng)查看下面的相關(guān)鏈接

相關(guān)文章

  • Go語(yǔ)言實(shí)現(xiàn)AES加密并編寫(xiě)一個(gè)命令行應(yīng)用程序

    Go語(yǔ)言實(shí)現(xiàn)AES加密并編寫(xiě)一個(gè)命令行應(yīng)用程序

    密碼學(xué)中的高級(jí)加密標(biāo)準(zhǔn)(Advanced Encryption Standard,AES),又稱Rijndael加密法,是經(jīng)常采用的一種區(qū)塊加密標(biāo)準(zhǔn)。本文就來(lái)用Go語(yǔ)言實(shí)現(xiàn)AES加密算法,需要的可以參考一下
    2023-02-02
  • Golang開(kāi)發(fā)使用gorm時(shí)打印SQL語(yǔ)句方式

    Golang開(kāi)發(fā)使用gorm時(shí)打印SQL語(yǔ)句方式

    這篇文章主要介紹了Golang開(kāi)發(fā)使用gorm時(shí)打印SQL語(yǔ)句方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • Go語(yǔ)言中如何實(shí)現(xiàn)并發(fā)

    Go語(yǔ)言中如何實(shí)現(xiàn)并發(fā)

    Go的并發(fā)機(jī)制通過(guò)協(xié)程和通道的簡(jiǎn)單性和高效性,使得編寫(xiě)并發(fā)代碼變得相對(duì)容易,這種并發(fā)模型被廣泛用于構(gòu)建高性能的網(wǎng)絡(luò)服務(wù)、并行處理任務(wù)和其他需要有效利用多核處理器的應(yīng)用程序,這篇文章主要介紹了在Go中如何實(shí)現(xiàn)并發(fā),需要的朋友可以參考下
    2023-09-09
  • 淺談golang結(jié)構(gòu)體偷懶初始化

    淺談golang結(jié)構(gòu)體偷懶初始化

    這篇文章主要介紹了淺談golang結(jié)構(gòu)體偷懶初始化,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • go日志庫(kù)logrus的安裝及快速使用

    go日志庫(kù)logrus的安裝及快速使用

    這篇文章主要為大家介紹了go日志庫(kù)logrus的安裝及快速使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • MacOS中 VSCode 安裝 GO 插件失敗問(wèn)題的快速解決方法

    MacOS中 VSCode 安裝 GO 插件失敗問(wèn)題的快速解決方法

    這篇文章主要介紹了MacOS中 VSCode 安裝 GO 插件失敗問(wèn)題的快速解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-05-05
  • 簡(jiǎn)單了解Go語(yǔ)言中函數(shù)作為值以及函數(shù)閉包的使用

    簡(jiǎn)單了解Go語(yǔ)言中函數(shù)作為值以及函數(shù)閉包的使用

    這篇文章主要介紹了簡(jiǎn)單了解Go語(yǔ)言中函數(shù)作為值以及函數(shù)閉包的使用,是golang入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-10-10
  • Go語(yǔ)言append切片添加元素的實(shí)現(xiàn)

    Go語(yǔ)言append切片添加元素的實(shí)現(xiàn)

    本文主要介紹了Go語(yǔ)言append切片添加元素的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Go?1.22版本新特性前瞻

    Go?1.22版本新特性前瞻

    這篇文章主要為大家介紹了Go?1.22版本新特性前瞻,包含語(yǔ)言的變化,編譯器、運(yùn)行時(shí)與工具鏈等應(yīng)用對(duì)比詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • 淺談Golang數(shù)據(jù)競(jìng)態(tài)

    淺談Golang數(shù)據(jù)競(jìng)態(tài)

    本文主要介紹了淺談Golang數(shù)據(jù)競(jìng)態(tài),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02

最新評(píng)論

沙雅县| 西贡区| 武陟县| 左云县| 庆阳市| 杭锦旗| 新营市| 大埔区| 达孜县| 苍溪县| 周宁县| 夏河县| 墨竹工卡县| 内丘县| 大理市| 贡嘎县| 重庆市| 紫阳县| 文水县| 中江县| 恭城| 诏安县| 乌鲁木齐市| 沛县| 贵州省| 达拉特旗| 东乌| 南召县| 绥江县| 宁津县| 丹棱县| 丘北县| 岫岩| 裕民县| 额济纳旗| 常熟市| 上栗县| 宜丰县| 虹口区| 呼和浩特市| 南康市|