29

[Introduction]匿名函数

 3 years ago
source link: https://studygolang.com/articles/29985
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

定义

匿名函数没有函数名只有函数体,在需要函数时再定义函数。函数可以当作变量赋值传递,与回调函数相似。Go语言随时支持在代码中定义匿名函数。

如下为声明一个匿名函数,在定义时直接声明:

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

也可以将匿名函数赋值给变量:

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

匿名性

匿名函数是不是真的没有名字,如下实例,调用并打印匿名函数的名字:

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")
}

输出结果如下:

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

应用

用作回调函数:

下面的代码实现对切片的遍历操作,遍历中访问每个元素的操作使用匿名函数来实现,用户传入不同的匿名函数体可以实现对元素不同的遍历操作,代码如下:

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)
}

使用匿名函数进行封装操作:

下面这段代码将匿名函数作为 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

有疑问加站长微信联系

iiUfA3j.png!web

很遗憾的说,推酷将在这个月底关闭。人生海海,几度秋凉,感谢那些有你的时光。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK