日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

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

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

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

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

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



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

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

其它編程語言中的閉包

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

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

在 Lua 語言中,將被捕獲的變量起了一個名字叫做 Upvalue,因為捕獲過程總是對閉包上方定義過的自由變量進行引用。

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

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

在閉包內部修改引用的變量

閉包對它作用域上部的變量可以進行修改,修改引用的變量會對變量進行實際修改,通過下面的例子來理解:

// 準備一個字符串
str := "hello world"

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

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

代碼說明如下:

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

代碼輸出:

hello dude

示例:閉包的記憶效應

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

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

package main

import (
    "fmt"
)

// 提供一個值, 每次調用函數(shù)會指定對值進行累加
func Accumulate(value int) func() int {

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

        // 累加
        value++

        // 返回一個累加值
        return value
    }
}

func main() {

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

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

    fmt.Println(accumulator())

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

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

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

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

代碼說明如下:

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

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

每調用一次 accumulator 都會自動對引用的變量進行累加。

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

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

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

package main

import (
    "fmt"
)

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

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

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

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

func main() {

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

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

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

代碼輸出如下:

high noon 150

代碼說明如下:

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

閉包還具有一定的封裝性,第 11 行的變量是 playerGen 的局部變量,playerGen 的外部無法直接訪問及修改這個變量,這種特性也與面向對象中強調的封裝性類似。


文章標題:創(chuàng)新互聯(lián)GO教程:Go語言閉包(Closure)——引用了外部變量的匿名函數(shù)
鏈接地址:http://www.5511xx.com/article/djdjosh.html