亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go回調函數和閉包怎么使用

發布時間:2022-04-18 10:55:52 來源:億速云 閱讀:134 作者:iii 欄目:開發技術

本篇內容介紹了“Go回調函數和閉包怎么使用”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

Go回調函數和閉包

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

  • 函數可以作為另一個函數的參數(典型用法是回調函數)

  • 函數可以返回另一個函數,即讓另一個函數作為這個函數的返回值(典型用法是閉包)

一般來說,附帶的還具備一個特性:函數可以作為一個值賦值給變量。

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

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

先簡單介紹下高階函數,然后介紹閉包。

高階函數示例

例如,將函數作為另一個函數的參數:

package main

import "fmt"

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

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

以下示例是函數返回另一個函數:

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))
}

回調函數(sort.SliceStable)

將函數B作為另一個函數A的參數,可以使得函數A的通用性更強,可以隨意定義函數B,只要滿足規則,函數A都可以去處理,這比較適合于回調函數。

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

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

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

例如:

package main

import (
	"fmt"
	"sort"
)

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

這里的排序函數就是回調函數。每取一次i和j對應的元素,就調用一次less函數。

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

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

還可以更強大更靈活。例如,按照字符大小順序來比較,而不是按照數值大小比較:

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對應的元素值轉換成字符串
		bi := strconv.FormatInt(int64(s1[i]), 10)
		bj := strconv.FormatInt(int64(s1[j]), 10)
		// 按字符順序降序排序
		return bi > bj
	})
	fmt.Println(s1)
}

按照字符串長度來比較:

package main

import (
	"fmt"
	"sort"
)

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

更嚴格地說是按字節數比較,因為len()操作字符串時獲取的是字節數而非字符數。如果要按照字符數比較,則使用如下代碼:

package main

import (
	"fmt"
	"sort"
)

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

閉包

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

簡單地說,閉包就是"一個函數+一個作用域環境"組成的特殊函數。這個函數可以訪問不是它自己內部的變量,也就是這個變量在其它作用域內,且這個變量是未賦值的,而是等待我們去賦值的。

例如:

package main

import "fmt"

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

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

    // 可以直接調用閉包
    // 因為閉包沒有賦值給變量,所以它稱為匿名閉包
    fmt.Println(f(3)(5))
}

上面的f()返回的g之所以稱為閉包函數,是因為它是一個函數,且引用了不在它自己范圍內的變量x,這個變量x是g所在作用域環境內的變量,因為x是未知、未賦值的自由變量。

如果x在傳遞給g之前是已經賦值的,那么閉包函數就不應該稱為閉包,因為這樣的閉包已經失去意義了。

下面這個g也是閉包函數,但這個閉包函數是自定義的,而不是通過函數返回函數得到的。

package main

import "fmt"

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

之所以這里的g也是閉包函數,是因為g中訪問了不屬于自己的變量x,而這個變量在閉包函數定義時是未綁定值的,也就是自由變量。

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

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

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

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

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

“Go回調函數和閉包怎么使用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

go
AI

白朗县| 盐山县| 郧西县| 东乌珠穆沁旗| 屏边| 灵武市| 阿克苏市| 翼城县| 乐清市| 社旗县| 微山县| 平阴县| 扎赉特旗| 泽普县| 定陶县| 洮南市| 含山县| 通海县| 宁武县| 怀集县| 敦煌市| 瓦房店市| 昌宁县| 东城区| 赣榆县| 九龙坡区| 额尔古纳市| 余庆县| 沙田区| 乡城县| 定襄县| 玛沁县| 凌云县| 剑川县| 贵定县| 潍坊市| 泰兴市| 贺兰县| 资溪县| 杭州市| 扶风县|