[Introduction]匿名函數

定義

匿名函數沒有函數名只有函數體,在須要函數時再定義函數。函數能夠看成變量賦值傳遞,與回調函數類似。Go語言隨時支持在代碼中定義匿名函數。html

以下爲聲明一個匿名函數,在定義時直接聲明:函數

func main() {
    log.Println("this is main func")
    func(name string) {
        log.Println("hello", name)
    }("Wzy_CC")
}
// out: 
// this is main func
// hello Wzy_CC

也能夠將匿名函數賦值給變量:post

f := func(name string) {
    log.Println("hello", name)
}
f("Wzy_CC") // 調用匿名函數

匿名性

匿名函數是否是真的沒有名字,以下實例,調用並打印匿名函數的名字:this

package main

import (
    "log"
    "runtime"
)

func printMyName() string {
    pc, _, _, _ := runtime.Caller(1) // 返回函數指針
    return runtime.FuncForPC(pc).Name()
}

func main() {
    var f func(string)
    f = func(name string) {
        log.Println("hello", name)
        log.Printf("f first assignment %s\n", printMyName())
    }
    f("Wzy")
    f = func(name string) {
        log.Println("hello2", name)
        log.Printf("f second assignment %s\n", printMyName())
    }
    f("Wzy")
}

輸出結果以下:.net

2020/07/22 16:50:36 hello Wzy  
2020/07/22 16:50:36 f first assignment main.main.func1   
2020/07/22 16:50:36 hello2 Wzy  
2020/07/22 16:50:36 f second assignment main.main.func2

看起來匿名函數彷佛仍是存在函數名的,自動編號func1~N命令行

應用

用做回調函數:設計

下面的代碼實現對切片的遍歷操做,遍歷中訪問每一個元素的操做使用匿名函數來實現,用戶傳入不一樣的匿名函數體能夠實現對元素不一樣的遍歷操做,代碼以下:3d

package main
import (
    "log"
)
// 遍歷切片的每一個元素, 經過給定函數進行元素訪問
func visit(list []int, f func(int)) { // 使用 visit() 函數將整個遍歷過程進行封裝
    for _, v := range list {
        f(v)
    }
}
func main() {
    // 使用匿名函數打印切片內容
    visit([]int{1, 2, 3, 4}, func(v int) { // 當要獲取遍歷期間的切片值時,只須要給 visit() 傳入一個回調參數便可
        log.Println(v)
    })
}

匿名函數做爲回調函數的設計在Go語言的系統包中也比較常見,strings 包中就有相似的設計,代碼以下:指針

func TrimFunc(s string, f func(rune) bool) string {
    return TrimRightFunc(TrimLeftFunc(s, f), f)
}

使用匿名函數進行封裝操做:code

下面這段代碼將匿名函數做爲 map 的鍵值,經過命令行參數動態調用匿名函數,代碼以下:

package main
import (
    "flag" // flag庫用於處理命令行參數
    "fmt"
)
// 定義命令行參數skill,從命令行輸入--skill能夠將=後的字符串傳入skillParam指針變量
var skillParam = flag.String("skill", "", "skill to perform") 

func main() {
    flag.Parse() // 解析命令行參數,解析完成後,skillParam指針變量將指向命令行傳入的值
    var skill = map[string]func(){ // 定義一個從字符串映射到func()的map,而後填充這個map
        "fire": func() { // 初始化map的鍵值對,值爲匿名函數
            fmt.Println("chicken fire")
        },
        "run": func() {
            fmt.Println("soldier run")
        },
        "fly": func() {
            fmt.Println("angel fly")
        },
    }
    // skillParam是一個*string類型的指針變量,使用*skillParam獲取到命令行傳過來的值,並在map中查找對應命令行參數指定的字符串的函數
    if f, ok := skill[*skillParam]; ok { 
        f()
    } else {
        fmt.Println("skill not found") // 若是在map定義中存在這個參數就調用,不然打印「技能沒有找到」
    }
}

運行代碼,結果以下:

PS C:\Users\W10\Desktop\本地工程\leetcode\test2> go run main.go --skill=fly
angel fly
PS C:\Users\W10\Desktop\本地工程\leetcode\test2> go run main.go --skill=run
soldier run

參考連接

Go語言匿名函數——沒有函數名字的函數

Go 每日一庫之 flag

相關文章
相關標籤/搜索