欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang 基礎(chǔ)之函數(shù)使用(匿名遞歸閉包)實(shí)例詳解

 更新時(shí)間:2023年10月19日 10:49:04   作者:帽兒山的槍手  
這篇文章主要為大家介紹了Golang 基礎(chǔ)之函數(shù)使用(匿名遞歸閉包)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

匿名函數(shù)

在Go語言中,函數(shù)可以像普通變量一樣被傳遞或使用,支持隨時(shí)在代碼里定義匿名函數(shù)。

匿名函數(shù)由一個(gè)不帶函數(shù)名的函數(shù)聲明和函數(shù)體組成。匿名函數(shù)的優(yōu)越性在于可以直接使用函數(shù)內(nèi)的變量,不必申明。

匿名函數(shù)有動(dòng)態(tài)創(chuàng)建的特性,該特性使得匿名函數(shù)不用通過參數(shù)傳遞的方式,就可以直接引用外部的變量。

使用

第一種用法:將匿名函數(shù)賦給變量,在通過變量調(diào)用匿名函數(shù)

sum := func(a, b int) int {
  return a + b
}
fmt.Println(sum(1, 2)) // 輸出 3

第二種用法:在定義匿名函數(shù)的時(shí)候直接使用,這種方式只能使用一次傳參

sum := func(a, b int) int {
    return a + b
}(1,2) // 傳入?yún)?shù)
fmt.Println(sum) // 輸出 3

第三種用法:將匿名函數(shù)賦給一個(gè)全局變量,匿名函數(shù)在當(dāng)前程序中都可以使用

package main
import "fmt"
var (
  // 全局變量必須首字母大寫
    Sum = func(a, b int) int {
        return a + b
    }
)
func main() {
    sum := Sum(1, 2)
    fmt.Println("sum=", sum) // 輸出 sum= 3
}

閉包

所謂“閉包”,指的是一個(gè)擁有許多變量和綁定了這些變量的環(huán)境的表達(dá)式(通常是一個(gè)函數(shù)),因而這些變量也是該表達(dá)式的一部分。

閉包(Closure),是引用了自由變量的函數(shù)。這個(gè)被引用的自由變量將和這個(gè)函數(shù)一同存在,即使已經(jīng)離開了創(chuàng)造它的環(huán)境也不例外。所以,有另一種說法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。閉包在運(yùn)行時(shí)可以有多個(gè)實(shí)例,不同的引用環(huán)境和相同的函數(shù)組合可以產(chǎn)生不同的實(shí)例。

可以理解為:閉包是匿名函數(shù)與匿名函數(shù)所引用環(huán)境的組合,類似常規(guī)函數(shù)引用全局變量處于一個(gè)包的環(huán)境。

閉包的優(yōu)點(diǎn)

  • 變量可以常駐內(nèi)存
  • 變量不污染全局

閉包里作用域返回的局部變量不會(huì)被立刻銷毀回收,可能會(huì)占用更多內(nèi)存過度使用閉包會(huì)導(dǎo)致性能下降。

使用

package main
import "fmt"
func main() {
    n := 0
    count := func() int {  // 這就是一個(gè)閉包
        n += 1
        return n
    }
    fmt.Println(count()) // 輸出 1
    fmt.Println(count()) // 輸出 2
}

常規(guī)函數(shù)、匿名函數(shù) + 全局變量 + 包就等同于閉包, count不僅存儲(chǔ)了函數(shù)的返回值,還存儲(chǔ)了閉包的狀態(tài)。

閉包被返回賦予一個(gè)同類型的變量時(shí),同時(shí)賦值的是整個(gè)閉包的狀態(tài),該狀態(tài)會(huì)一直存在外部被賦值的變量count中,直到count被銷毀,整個(gè)閉包生命周期結(jié)束。

也可以寫成下列形式

package main
import "fmt"
func Count() func() int { // 返回函數(shù)
    n := 0
    return func() int {
        n++
        return n
    }
}
func main() {
    count := Count()
    fmt.Println(count()) // 輸出 1
    fmt.Println(count()) // 輸出 2
}

高級(jí)閉包特性,比如并發(fā)中的閉包。 將放到后面章節(jié)為大家介紹。

遞歸函數(shù)

遞歸,就是在運(yùn)行的過程中調(diào)用自己。

一個(gè)函數(shù)調(diào)用自己, 就叫做遞歸函數(shù)。

構(gòu)成遞歸具備的條件:

  • 子問題需要與原始問題為同樣的事,且更為簡單。
  • 不能無限制地調(diào)用本身,須有個(gè)出口,化簡為非遞歸狀況處理。

使用

舉例:數(shù)字階乘

一個(gè)正整數(shù)的階乘是所有小于及等于該數(shù)的正整數(shù)的積,并且0的階乘為1。

package main
import "fmt"
func factorial(i int) int {  // 解讀為 5*4*3*2*1=120 
    if i <= 1 {
        return 1
    }
    return i * factorial(i-1)
}
func main() {
    var i int = 5
    fmt.Printf("%d\n", factorial((i))) // 120
}
1808年,基斯頓·卡曼引進(jìn)這個(gè)表示法。

舉例:裴波那契數(shù)列(Fibonacci)

這個(gè)數(shù)列從第3項(xiàng)開始,每一項(xiàng)都等于前兩項(xiàng)之和。

package main
import "fmt"
func fibonaci(i int) int {    
    if i == 0 {
        return 0    
    }
    if i == 1 {
        return 1
    }    
    return fibonaci(i-1) + fibonaci(i-2)
}
func main() {
    var i int
    for i = 0; i < 10; i++ {
        fmt.Printf("%d ", fibonaci(i)) // 0 1 1 2 3 5 8 13 21 34
    }
}

延遲調(diào)用 (defer)

在基礎(chǔ)語法中已經(jīng)介紹了defer延遲調(diào)用的使用,今天深入了解使用一下defer機(jī)制。

defer特性

  • 關(guān)鍵字 defer 用于注冊(cè)延遲調(diào)用。
  • 這些調(diào)用直到 return 前才被執(zhí)。因此,可以用來做資源清理。
  • 多個(gè)defer語句,按先進(jìn)后出的方式執(zhí)行。
  • defer語句中的變量,在defer聲明時(shí)就決定了。
  • 某個(gè)延遲調(diào)用發(fā)生錯(cuò)誤,這些調(diào)用依舊會(huì)被執(zhí)行。

defer后面的語句在執(zhí)行的時(shí)候,函數(shù)調(diào)用的參數(shù)會(huì)被保存起來,但是不執(zhí)行。也就是復(fù)制了一份。

defer用途

  • 關(guān)閉文件句柄
  • 鎖資源釋放
  • 數(shù)據(jù)庫連接釋放

使用

多個(gè) defer 注冊(cè),按 FILO 次序執(zhí)行 ( 先進(jìn)后出 ) 原則。

package main
func main() {
    defer println("1") // 先進(jìn)來, 最后出去
    defer println("2")
    defer println("3") // 最后進(jìn)來, 先出去
}

輸出

3
2
1

延遲調(diào)用參數(shù)在注冊(cè)時(shí)求值或復(fù)制,可以用指針或閉包 “延遲” 讀取。

package main

import "fmt"

func main() {
    x, y := 10, 100
    defer func(i int) {
        fmt.Printf("defer x = %v, y = %v\n", i, y) // y 閉包引用
    }(x) // x 被復(fù)制

    x += 10
    y += 20
    println("x = ", x, "y = ", y)
}

輸出

x =  20 y =  120
defer x = 10, y = 120

defer和return兩者執(zhí)行順序

  • 有名返回值 (函數(shù)返回值為已經(jīng)命名的返回值)
package main
import "fmt"
func foo() (i int) { // 3.return i 值
    i = 0
    defer func() {
    fmt.Println(i) // 2.讀取臨時(shí)變量地址(返回值)
    }()
    return 2 // 1.返回值賦值,寫入臨時(shí)變量
}
func main() {
    foo()
}

輸出

2

在 foo() 返回值的函數(shù)中 (這里返回值為 i),執(zhí)行 return 2 的時(shí)候?qū)嶋H上已經(jīng)將i 的值重新賦值為2。 所以defer closure輸出結(jié)果為2。

解析:

return 的機(jī)制:1.首先將返回值放到一個(gè)臨時(shí)變量中(為返回值賦值) 2. 然后將返回值返回到被調(diào)用處。

而defer函數(shù)恰在return的兩個(gè)操作之間執(zhí)行。

執(zhí)行順序是: 先為返回值賦值,即將返回值放到一個(gè)臨時(shí)變量中,然后執(zhí)行defer,然后return到函數(shù)被調(diào)用處。

  • 無名返回值 (即函數(shù)返回值為沒有命名的函數(shù)返回值)
package main
import "fmt"
func foo() int {
    var i int
    defer func() {
        i++ // 這個(gè)地方 i,不是臨時(shí)變量
        fmt.Println("defer = ", i) // 輸出 defer = 1
    }()
    return i // 返回值賦值,寫入臨時(shí)變量
}
func main() {
    fmt.Println("return = ", foo()) // 輸出 return = 0
}

 解析:return 先把返回值放到一個(gè)臨時(shí)變量中,defer函數(shù)無法獲取到這個(gè)臨時(shí)變量地址 (沒有函數(shù)返回值),所以無論defer函數(shù)做任何操作,都不會(huì)對(duì)最終返回值造成任何變動(dòng)。

以上就是Golang 基礎(chǔ)之函數(shù)使用(匿名遞歸閉包)實(shí)例詳解的詳細(xì)內(nèi)容,更多關(guān)于Golang 匿名遞歸函數(shù)閉包的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論