日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Go 学习笔记(18)— 函数(04)[闭包定义、闭包修改变量、闭包记忆效应、闭包实现生成器、闭包复制原对象指针]

發布時間:2023/11/27 生活经验 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Go 学习笔记(18)— 函数(04)[闭包定义、闭包修改变量、闭包记忆效应、闭包实现生成器、闭包复制原对象指针] 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 閉包定義

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

函數 + 引用環境 = 閉包

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

Go 語言閉包函數的定義:當匿名函數引用了外部作用域中的變量時就成了閉包函數,閉包函數是函數式編程語言的核心。

也就是匿名函數可以會訪問其所在的外層函數內的局部變量。當外層函數運行結束后,匿名函數會與其使用的外部函數的局部變量形成閉包。

2. 閉包示例

2.1 閉包修改變量

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

package mainimport "fmt"func main() {// 準備一個字符串str := "hello world"fmt.Println("str is ", str)// 創建一個匿名函數foo := func() {// 匿名函數中訪問str// 在匿名函數中并沒有定義 str,str 的定義在匿名函數之前,此時,str 就被引用到了匿名函數中形成了閉包。str = "hello dude"}// 調用匿名函數, 執行閉包,此時 str 發生修改,變為 hello dude。foo()fmt.Println("str is ", str)
}

代碼輸出:

str is  hello world
str is  hello dude

2.2 閉包記憶效應

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

package mainimport ("fmt"
)/*
累加器生成函數,這個函數輸出一個初始值,
調用時返回一個為初始值創建的閉包函數
*/
func Accumulate(value int) func() int {// 返回一個閉包,每次返回會創建一個新的函數實例return func() int {// 累加,對引用的 Accumulate 參數變量進行累加,注意 value 不是上一行匿名函數定義的,但是被這個匿名函數引用,所以形成閉包。value++// 返回一個累加值return value}
}func main() {// 創建一個累加器,初始值為 1,返回的 accumulator 是類型為 func()int 的函數變量。accumulator := Accumulate(1)// 累加1并打印fmt.Println(accumulator())fmt.Println(accumulator())// 打印累加器的函數地址fmt.Printf("%p\n", &accumulator)// 創建一個累加器, 初始值為10accumulator2 := Accumulate(10)// 累加1并打印fmt.Println(accumulator2())// 打印累加器的函數地址fmt.Printf("%p\n", &accumulator2)
}

輸出結果:

2
3
0xc00000e030
11
0xc00000e040

可以看出 accumulator 與 accumulator2 輸出的函數地址不同,因此它們是兩個不同的閉包實例。

package mainimport "fmt"func add() func(int) int {var x intreturn func(y int) int {x += yreturn x}
}
func main() {var f = add()fmt.Println(f(1)) //1fmt.Println(f(2)) //3fmt.Println(f(3)) //6f1 := add()fmt.Println(f1(4)) //4fmt.Println(f1(5)) //9
}

add() 函數賦值給變量 f,那么 f(1) 就相當于執行其內部的匿名函數 func(y int)。所以 f(1) 其實執行的是 x = x+y,此時 x 沒有給值默認為 0,y 為 1,最終返回 x 的值是 1。

f(2) 同樣執行其內部的匿名函數 func(y int),所以 f(2) 其實執行的是 x = x+y。此時 x 已經是 1,y 為 2,最終返回 x 的值是 3,依次類推執行。

2.3 閉包實現生成器

玩家生成器的實現:

package mainimport ("fmt"
)// 創建一個玩家生成器, 輸入名稱, 輸出生成器
func playerGen(name string) func() (string, int) {// 血量一直為150hp := 150// 返回創建的閉包return func() (string, int) {// 將 hp 和 name 變量引用到匿名函數中形成閉包。return name, hp}
}func main() {// 創建一個玩家生成器generator := playerGen("wohu")// 返回玩家的名字和血量name, hp := generator()// 打印值fmt.Println(name, hp)   // wohu 150
}

2.4 閉包復制原對象指針

閉包復制的是原對象指針,這就很容易解釋延遲引用現象。

package mainimport "fmt"func test() func() {x := 100fmt.Printf("x (%p) = %d\n", &x, x)return func() {fmt.Printf("x (%p) = %d\n", &x, x)}
}func main() {f := test()f()
}

輸出:

x (0xc000018068) = 100
x (0xc000018068) = 100

3. 對比 Python 閉包

def fun1():sum = 0def fun2(v):nonlocal sumsum += vreturn sumreturn fun2a = fun1()
for i in range(10):print(a(i))0
1
3
6
10
15
21
28
36
45

代碼解析:
fun1 返回的不是一個值,而是一個函數 fun2,a = fun2,所以 a(i) 會打印 sum 的值。

為什么 sum 一直在加呢,函數里的值為什么可以帶到函數體外呢?
其實可以把閉包看做一個類, sum 就是類里的屬性,fun2 就是類的方法,所以 fun2 可以使用 sum(自由變量)。

nonlocal 聲明的變量不是局部變量,也不是全局變量,而是外部嵌套函數內的變量。嵌套函數 fun2 中的 sum 受到了影響,顯示 fun2 中的 sum 是 fun1 函數中的局部變量。

總結

以上是生活随笔為你收集整理的Go 学习笔记(18)— 函数(04)[闭包定义、闭包修改变量、闭包记忆效应、闭包实现生成器、闭包复制原对象指针]的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。