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

詳解golang中的閉包與defer

 更新時間:2022年09月07日 08:57:23   作者:MY.BOO  
閉包一個函數(shù)與其相關的引用環(huán)境組合的一個實體,其實可以理解為面向對象中類中的屬性與方法,這篇文章主要介紹了golang的閉包與defer,需要的朋友可以參考下

閉包與defer

1.閉包

閉包 : 一個函數(shù)與其相關的引用環(huán)境組合的一個實體,其實可以理解為面向對象中類中的屬性與方法。
如代碼塊中,函數(shù)function的返回值(匿名函數(shù))與變量n就是1個閉包。
該匿名函數(shù)就相當于類中的方法 變量n相當于類中的屬性

// 無形參 返回值是該匿名函數(shù)
func function() func(int) int {
    var n int = 10           // 相當于類屬性
    return func(x int) int { //匿名函數(shù)
        x = x + n
        
        return x
    }
}
var f func(int) int = function()
fmt.Println(f(1)) // 11 
fmt.Println(f(2)) // 13

再舉幾個例子:

//示例1
func adder2(x int) func(int) int {
	return func(y int) int {
		x += y
		return x
	}
}
func main() {
	var f = adder2(10)
	fmt.Println(f(10)) //20
	fmt.Println(f(20)) //40
	fmt.Println(f(30)) //70

	f1 := adder2(20)
	fmt.Println(f1(40)) //60
	fmt.Println(f1(50)) //110
}
//示例2
func makeSuffixFunc(suffix string) func(string) string {
	return func(name string) string {
		if !strings.HasSuffix(name, suffix) {
			return name + suffix
		}
		return name
	}
}

func main() {
	jpgFunc := makeSuffixFunc(".jpg")
	txtFunc := makeSuffixFunc(".txt")
	fmt.Println(jpgFunc("test")) //test.jpg
	fmt.Println(txtFunc("test")) //test.txt
}

2.defer

1.defer 是 Go 語言提供的一種用于注冊延遲調用的機制,每一次 defer 都會把函數(shù)壓入棧中,當前函數(shù)返回前再把延遲函數(shù)取出并執(zhí)行。

defer 定義的函數(shù)會先進入一個棧,函數(shù) return 前,會按先進后出(FILO)的順序執(zhí)行。也就是說最先被定義的 defer 語句最后執(zhí)行。

2.defer 語句定義時,對 外部變量的引用 是有兩種方式的,分別是作為 函數(shù)參數(shù) 和作為 閉包引用。

  • 作為 函數(shù)參數(shù),則在 defer 定義時 就把值傳遞給 defer,并被 緩存 起來;
  • 作為 閉包引用 的話,則會在 defer 函數(shù)真正調用時根據(jù)整個上下文確定當前的值。

下面就分別對這兩種情況舉例子。

情況一:

func trace(str string) string {
    fmt.Println("entering " + str)
    return str
}
func leave(str string) {
    fmt.Println("leaving " + str)
}
func point() {
    defer leave(trace("point"))
    fmt.Println("in point")
}
func main() {
    point()
}

//輸出結果:
//entering point
//in point
//leaving point

這是第一種情況,defer的函數(shù)接受的參數(shù)在它入棧的時候就被緩存下來了。

再舉個例子:

func main() {
    a := 1
    b := 2
    defer calc("1", a, calc("10", a, b))
    a = 0
    defer calc("2", a, calc("20", a, b))
    b = 1
}

func calc(index string, a, b int) int {
    ret := a + b
    fmt.Println(index, a, b, ret)
    return ret
}

//10 1 2 3
//20 0 2 2
//2 0 2 2
//1 1 3 4

情況二:

要完全理解第二條規(guī)則,需要了解 returndefer 是怎么運行的。

函數(shù)內的 return xxx 并不是一個原子執(zhí)行的返回:即不是先執(zhí)行 return xxx 再執(zhí)行 defer,也不是先執(zhí)行 defer 再執(zhí)行 return xxx。而是將 return xxx 拆分開來,經(jīng)過編譯后執(zhí)行過程如下:

1. 返回變量 = xxx
2. 調用 defer 函數(shù)(有可能更新返回變量的值)
3. return 返回變量。
1.
func f1() (r int) {
    defer func() {
        r++
    }()
    return 0
}

2.
func f2() (r int) {
    t := 5
    defer func() {
        t = t + 5
    }()
    return t
}

3.
func f3() (r int) {
    defer func(r int) { // 作為函數(shù)參數(shù)傳入 defer 函數(shù)
        r = r + 5 
    }(r)
    return 1
}
拆解:
1.r = 0 // 1. 賦值
func() { // 2. 運行 defer 函數(shù) r++,r = 1
    r++
}()
return r // 3. return,即返回結果為 1

2.r = t (= 5) // 1. 賦值,r 取值 5
func() { // 2. 執(zhí)行 defer 函數(shù),執(zhí)行后 t = 10,但 r = 5
    t = t + 5
}()
return r // 3. return r,即返回 5

3.r = 1 // 1. 賦值, r 取值 1
func(r int) { // 2. 執(zhí)行 defer 函數(shù),但作為函數(shù)參數(shù)傳入(緩存值為0)
    r = r + 5 // 執(zhí)行后 r = 0 + 5 = 5,但這是局部變量,函數(shù)外仍是 1
}(r)
return r // 3. return r, 即返回 1

踩坑點:

func increaseA() int {
    var i int
    defer func() {
        i++
    }()
    return i
}

注意,上面這段代碼的返回值是匿名的,所以結果返回0。

現(xiàn)在我們再以2個例子來做總結和鞏固:

type Person struct {
    age int
}

func main() {
    person := &Person{28}

    // 1. 
    defer fmt.Println(person.age)

    // 2.
    defer func(p *Person) {
        fmt.Println(p.age)
    }(person)  

    // 3.
    defer func() {
        fmt.Println(person.age)
    }()

    person.age = 29
}

參考答案及解析:29 29 28。變量 person 是一個指針變量 。

1.person.age 此時是將 28 當做 defer 函數(shù)的參數(shù),會把 28 緩存在棧中,等到最后執(zhí)行該 defer 語句的時候取出,即輸出 28;

2.defer 緩存的是結構體 Person{28} 的地址,最終 Person{28} 的 age 被重新賦值為 29,所以 defer 語句最后執(zhí)行的時候,依靠緩存的地址取出的 age 便是 29,即輸出 29;

3.閉包引用,輸出 29;

又由于 defer 的執(zhí)行順序為先進后出,即 3 2 1,所以輸出 29 29 28。

type Person struct {
    age int
}

func main() {
    person := &Person{28}

    // 1.
    defer fmt.Println(person.age)

    // 2.
    defer func(p *Person) {
        fmt.Println(p.age)
    }(person)

    // 3.
    defer func() {
        fmt.Println(person.age)
    }()

    person = &Person{29}
}

參考答案及解析:29 28 28。這道題在第 19 天題目的基礎上做了一點點小改動,前一題最后一行代碼

person.age = 29 是修改引用對象的成員 age,這題最后一行代碼 person = &Person{29} 是修改引用對象本身,來看看有什么區(qū)別。

1.person.age 這一行代碼跟之前含義是一樣的,此時是將 28 當做 defer 函數(shù)的參數(shù),會把 28 緩存在棧中,等到最后執(zhí)行該 defer 語句的時候取出,即輸出 28;

2.defer 緩存的是結構體 Person{28} 的地址,這個地址指向的結構體沒有被改變,最后 defer 語句后面的函數(shù)執(zhí)行的時候取出仍是 28;

3.閉包引用,person 的值已經(jīng)被改變,指向結構體 Person{29},所以輸出 29.

由于 defer 的執(zhí)行順序為先進后出,即 3 2 1,所以輸出 29 28 28。

最后打個小廣告:最近朋友建立了一個倉庫,記錄golang開發(fā)中踩過的坑和遇到的問題,歡迎大家把自己遇到的問題記錄下來,共同進步!
倉庫地址:https://github.com/remake100/go-study

到此這篇關于golang的閉包與defer的文章就介紹到這了,更多相關golang defer閉包內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 深入探索Go語言中的高效數(shù)據(jù)結構堆

    深入探索Go語言中的高效數(shù)據(jù)結構堆

    堆,作為一種基本的數(shù)據(jù)結構,以其在優(yōu)先隊列和排序算法中提供高效解決方案的能力而聞名。在本文中,我們將深入探討堆的內部工作原理,包括其特性、實現(xiàn)細節(jié)以及在現(xiàn)代編程中的應用
    2008-06-06
  • GO語言Defer用法實例分析

    GO語言Defer用法實例分析

    這篇文章主要介紹了GO語言Defer用法,實例分析了Defer的使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02
  • Go之集合slice的實現(xiàn)

    Go之集合slice的實現(xiàn)

    本文主要介紹了Go之集合slice的實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Go語言程序查看和診斷工具詳解

    Go語言程序查看和診斷工具詳解

    這篇文章主要為大家詳細介紹了Go語言程序查看和診斷工具,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • GoLang逃逸分析講解

    GoLang逃逸分析講解

    我們都知道go語言中內存管理工作都是由Go在底層完成的,這樣我們可以不用過多的關注底層的內存問題。本文主要總結一下?Golang內存逃逸分析,需要的朋友可以參考以下內容,希望對大家有幫助
    2022-12-12
  • Go語言struct類型介紹

    Go語言struct類型介紹

    這篇文章主要介紹了Go語言struct類型介紹,本文講解了struct的2種聲明方式,struct的匿名字段等內容,需要的朋友可以參考下
    2015-01-01
  • GO語言 復合類型專題

    GO語言 復合類型專題

    這篇文章主要介紹了GO語言 復合類型的的相關資料,文中講解非常細致,代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下
    2020-06-06
  • Golang判斷兩個鏈表是否相交的方法詳解

    Golang判斷兩個鏈表是否相交的方法詳解

    這篇文章主要為大家詳細介紹了如何通過Golang判斷兩個鏈表是否相交,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-03-03
  • goland2020.2.x永久激活碼破解詳細教程親測可用(Windows Linux Mac)

    goland2020.2.x永久激活碼破解詳細教程親測可用(Windows Linux Mac)

    這篇文章主要介紹了goland2020.2.x永久激活碼破解詳細教程親測可用(Windows Linux Mac) ,對goland激活碼注冊碼相關知識感興趣的朋友跟隨小編一起看看吧
    2020-11-11
  • 詳解Go?sync?同步原語

    詳解Go?sync?同步原語

    Go?中不僅有?channel?這種?CSP?同步機制,還有?sync.Mutex、sync.WaitGroup?等比較原始的同步原語,使用它們,可以更靈活的控制數(shù)據(jù)同步和多協(xié)程并發(fā),這篇文章主要介紹了Go?sync?同步原語,需要的朋友可以參考下
    2023-12-12

最新評論

新蔡县| 昆明市| 论坛| 金昌市| 广丰县| 茂名市| 孝感市| 襄垣县| 昭觉县| 桃园市| 禹城市| 江山市| 乡城县| 偏关县| 杭州市| 岳阳县| 昭平县| 浑源县| 察哈| 忻城县| 日照市| 通州市| 海门市| 潍坊市| 麦盖提县| 右玉县| 安龙县| 富裕县| 炎陵县| 吐鲁番市| 曲麻莱县| 崇仁县| 诸暨市| 信阳市| 阳曲县| 涞源县| 宜宾市| 哈尔滨市| 桦南县| 台南市| 安顺市|