iT邦幫忙

2022 iThome 鐵人賽

DAY 27
0
自我挑戰組

跟著 Go 實戰聖經 一起自學 Go系列 第 27

DAY 27 Go 語言 函式 (function) 匿名函式與閉包

  • 分享至 

  • xImage
  •  

昨天介紹到參數不定函式,今天立馬來繼續學習匿名函式~

具名函式

目前為止我們的函式都是必須在套件層級宣告的 具名函式

func myFavorite() {  // myFavorite 便是此函式的名稱
    // 執行的程式碼
}

匿名函式

但其實也有另一種 匿名函式(anonymous functions) ,顧名思義是沒有名稱的函式。

匿名函式的特性

  1. 沒有函式名稱
  2. 只能在其他函式內被宣告
  3. 只能使用一次
  4. 可以實作閉包
  5. 可以搭配 defer 敘述延後執行程式碼

宣告匿名函式

以下使用範例 1 試著在 main 函式裡宣告匿名函式:

範例 1:

package main

import "fmt"

func main() {
    func() {  // 在 main 裡宣告匿名函式
        fmt.Println("奇犽")
    }()  // 用 () 立即呼叫這個匿名函式
}

範例 1(執行結果):

奇犽

若有需要傳給匿名函式的引數,可以將引數寫在最後的小括弧中,如範例 2:

範例 2:

package main

import "fmt"

func main() {
    myFavorite := "奇犽"
    func (str string) {
        fmt.Println(str)  
    }(myFavorite)  // 傳給函式的引數寫在 () 小括號內
}

範例 2(執行結果):

奇犽

範例 1.2 我們都是使用 () 小括號來立即執行匿名函式,但也可以將函式存在變數中,通過變數來呼叫匿名函式:

範例 3:

package main

import "fmt"

func main() {
    f := func() {
        fmt.Println("變數裡的匿名函式")
    }
    fmt.Println("我是本來 main 函式裡要印出的字") // func 是逐行執行,所以會先印出這句
    f()  // 在此行才通過變數呼叫匿名函式,這時控制權才轉向上方的匿名函式,進而印出函式內的字
}

範例 3(執行結果):

我是本來 main 函式裡要印出的字
變數裡的匿名函式

建立閉包

閉包(closure) 是匿名函式的形式之一,一般來說,函式在離開範圍後便無法引用父函式的區域變數,但是閉包便有辦法:
範例 4:

package main

import "fmt"

func main() {
    add := addFunc() // 接收傳回的 addFunc 函式
    fmt.Println(add())
    fmt.Println(add())
    fmt.Println(add())
}

func addFunc() func() int {
    i := 0  // 定義 i 為匿名函式的父函式內的變數
    return func() int {  // 回傳一個匿名函式
        i++
        return i
    }
}

範例 4(執行結果):

1
2
3

範例 4 我們呼叫 add() 函式會發現他每次印出的值都有加一,代表他有記得 i 的值,這個我們稱為閉包,也可以稱為 語意閉包(lexical closure) ,閉包即使離開父函式執行範圍,也有能夠記住父函式變數的特性。

自訂函式型別

在 Go 語言中,函式跟字串一樣也是一種型別,因為是一種型別,代表我們可以將函式當作引數、回傳值,或是像範例 4 一樣拿函式賦值給變數。
若想把函式當成引數,就應該要明確指明接收參數型別,而函式型別定義就是我們前幾天有介紹到的 參數傳回值型別 ,若想要更好辨識或是閱讀,我們可以使用 自訂函式型別

type myFavorite func()  // 自訂一個名為 myFavorite 的函式型別,但不需要輸入參數也沒有傳回值
type myFavorite func(string) string  // 自訂一個名為 myFavorite 的函式型別,接收一個字串參數,以及傳回一個字串型別的值

今天介紹了匿名函式與閉包,那明天我們繼續了解函式的最後一部份 defer ,明天見~~~


上一篇
DAY 26 Go 語言 函式 (function) 參數不定函式
下一篇
DAY 28 Go 語言 函式 (function) 用 defer 延後執行函式
系列文
跟著 Go 實戰聖經 一起自學 Go30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言