日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
創(chuàng)新互聯(lián)GO教程:Go語言閉包(Closure)——引用了外部變量的匿名函數(shù)

Go語言中閉包是引用了自由變量的函數(shù),被引用的自由變量和函數(shù)一同存在,即使已經(jīng)離開了自由變量的環(huán)境也不會(huì)被釋放或者刪除,在閉包中可以繼續(xù)使用這個(gè)自由變量,因此,簡(jiǎn)單的說:

公司主營業(yè)務(wù):網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)推出望都免費(fèi)做網(wǎng)站回饋大家。

函數(shù) + 引用環(huán)境 = 閉包

同一個(gè)函數(shù)與不同引用環(huán)境組合,可以形成不同的實(shí)例,如下圖所示。



圖:閉包與函數(shù)引用

一個(gè)函數(shù)類型就像結(jié)構(gòu)體一樣,可以被實(shí)例化,函數(shù)本身不存儲(chǔ)任何信息,只有與引用環(huán)境結(jié)合后形成的閉包才具有“記憶性”,函數(shù)是編譯期靜態(tài)的概念,而閉包是運(yùn)行期動(dòng)態(tài)的概念。

其它編程語言中的閉包

閉包(Closure)在某些編程語言中也被稱為 Lambda 表達(dá)式。

閉包對(duì)環(huán)境中變量的引用過程也可以被稱為“捕獲”,在 C++11 標(biāo)準(zhǔn)中,捕獲有兩種類型,分別是引用和復(fù)制,可以改變引用的原值叫做“引用捕獲”,捕獲的過程值被復(fù)制到閉包中使用叫做“復(fù)制捕獲”。

在 Lua 語言中,將被捕獲的變量起了一個(gè)名字叫做 Upvalue,因?yàn)椴东@過程總是對(duì)閉包上方定義過的自由變量進(jìn)行引用。

閉包在各種語言中的實(shí)現(xiàn)也是不盡相同的,在 Lua 語言中,無論閉包還是函數(shù)都屬于 Prototype 概念,被捕獲的變量以 Upvalue 的形式引用到閉包中。

C++ 與 C# 中為閉包創(chuàng)建了一個(gè)類,而被捕獲的變量在編譯時(shí)放到類中的成員中,閉包在訪問被捕獲的變量時(shí),實(shí)際上訪問的是閉包隱藏類的成員。

在閉包內(nèi)部修改引用的變量

閉包對(duì)它作用域上部的變量可以進(jìn)行修改,修改引用的變量會(huì)對(duì)變量進(jìn)行實(shí)際修改,通過下面的例子來理解:

// 準(zhǔn)備一個(gè)字符串
str := "hello world"

// 創(chuàng)建一個(gè)匿名函數(shù)
foo := func() {
   
    // 匿名函數(shù)中訪問str
    str = "hello dude"
}

// 調(diào)用匿名函數(shù)
foo()

代碼說明如下:

  • 第 2 行,準(zhǔn)備一個(gè)字符串用于修改。
  • 第 5 行,創(chuàng)建一個(gè)匿名函數(shù)。
  • 第 8 行,在匿名函數(shù)中并沒有定義 str,str 的定義在匿名函數(shù)之前,此時(shí),str 就被引用到了匿名函數(shù)中形成了閉包。
  • 第 12 行,執(zhí)行閉包,此時(shí) str 發(fā)生修改,變?yōu)?hello dude。

代碼輸出:

hello dude

示例:閉包的記憶效應(yīng)

被捕獲到閉包中的變量讓閉包本身擁有了記憶效應(yīng),閉包中的邏輯可以修改閉包捕獲的變量,變量會(huì)跟隨閉包生命期一直存在,閉包本身就如同變量一樣擁有了記憶效應(yīng)。

累加器的實(shí)現(xiàn):

package main

import (
    "fmt"
)

// 提供一個(gè)值, 每次調(diào)用函數(shù)會(huì)指定對(duì)值進(jìn)行累加
func Accumulate(value int) func() int {

    // 返回一個(gè)閉包
    return func() int {

        // 累加
        value++

        // 返回一個(gè)累加值
        return value
    }
}

func main() {

    // 創(chuàng)建一個(gè)累加器, 初始值為1
    accumulator := Accumulate(1)

    // 累加1并打印
    fmt.Println(accumulator())

    fmt.Println(accumulator())

    // 打印累加器的函數(shù)地址
    fmt.Printf("%p\n", &accumulator)

    // 創(chuàng)建一個(gè)累加器, 初始值為1
    accumulator2 := Accumulate(10)

    // 累加1并打印
    fmt.Println(accumulator2())

    // 打印累加器的函數(shù)地址
    fmt.Printf("%p\n", &accumulator2)
}

代碼說明如下:

  • 第 8 行,累加器生成函數(shù),這個(gè)函數(shù)輸出一個(gè)初始值,調(diào)用時(shí)返回一個(gè)為初始值創(chuàng)建的閉包函數(shù)。
  • 第 11 行,返回一個(gè)閉包函數(shù),每次返回會(huì)創(chuàng)建一個(gè)新的函數(shù)實(shí)例。
  • 第 14 行,對(duì)引用的 Accumulate 參數(shù)變量進(jìn)行累加,注意 value 不是第 11 行匿名函數(shù)定義的,但是被這個(gè)匿名函數(shù)引用,所以形成閉包。
  • 第 17 行,將修改后的值通過閉包的返回值返回。
  • 第 24 行,創(chuàng)建一個(gè)累加器,初始值為 1,返回的 accumulator 是類型為 func()int 的函數(shù)變量。
  • 第 27 行,調(diào)用 accumulator() 時(shí),代碼從 11 行開始執(zhí)行匿名函數(shù)邏輯,直到第 17 行返回。
  • 第 32 行,打印累加器的函數(shù)地址。

對(duì)比輸出的日志發(fā)現(xiàn) accumulator 與 accumulator2 輸出的函數(shù)地址不同,因此它們是兩個(gè)不同的閉包實(shí)例。

每調(diào)用一次 accumulator 都會(huì)自動(dòng)對(duì)引用的變量進(jìn)行累加。

示例:閉包實(shí)現(xiàn)生成器

閉包的記憶效應(yīng)被用于實(shí)現(xiàn)類似于 設(shè)計(jì)模式中工廠模式的生成器,下面的例子展示了創(chuàng)建一個(gè)玩家生成器的過程。

玩家生成器的實(shí)現(xiàn):

package main

import (
    "fmt"
)

// 創(chuàng)建一個(gè)玩家生成器, 輸入名稱, 輸出生成器
func playerGen(name string) func() (string, int) {

    // 血量一直為150
    hp := 150

    // 返回創(chuàng)建的閉包
    return func() (string, int) {

        // 將變量引用到閉包中
        return name, hp
    }
}

func main() {

    // 創(chuàng)建一個(gè)玩家生成器
    generator := playerGen("high noon")

    // 返回玩家的名字和血量
    name, hp := generator()

    // 打印值
    fmt.Println(name, hp)
}

代碼輸出如下:

high noon 150

代碼說明如下:

  • 第 8 行,playerGen() 需要提供一個(gè)名字來創(chuàng)建一個(gè)玩家的生成函數(shù)。
  • 第 11 行,聲明并設(shè)定 hp 變量為 150。
  • 第 14~18 行,將 hp 和 name 變量引用到匿名函數(shù)中形成閉包。
  • 第 24 行中,通過 playerGen 傳入?yún)?shù)調(diào)用后獲得玩家生成器。
  • 第 27 行,調(diào)用這個(gè)玩家生成器函數(shù),可以獲得玩家的名稱和血量。

閉包還具有一定的封裝性,第 11 行的變量是 playerGen 的局部變量,playerGen 的外部無法直接訪問及修改這個(gè)變量,這種特性也與面向?qū)ο笾袕?qiáng)調(diào)的封裝性類似。


本文標(biāo)題:創(chuàng)新互聯(lián)GO教程:Go語言閉包(Closure)——引用了外部變量的匿名函數(shù)
URL網(wǎng)址:http://www.dlmjj.cn/article/djdjosh.html