美文网首页
golang中匿名函数看这篇就够啦

golang中匿名函数看这篇就够啦

作者: 护念 | 来源:发表于2023-11-15 22:00 被阅读0次

匿名函数

匿名函数就是没有名称的函数,主要记住它可以用于各种类型(切片、结构体、map等)中就行。

1. 一等公民

golang中的函数是一等公民 —— 它能做类型、变量、参数等传递。

package main

import "fmt"

func main() {

    // 切片中充当元素
    d := []func(int) int{
        func(x int) int { return x + 2 },
        func(y int) int { return y + 2 },
    }

    fmt.Println(d[0](2))

    // 结构体中字段
    s := struct {
        fn func(int) int // 结构体这里没有逗号
    }{
        fn: func(x int) int { return x + 100 },
    }

    fmt.Println(s.fn(2))

    // map中充当value
    m := make(map[string]func(int) int) // map 可以不指定长度
    m["first"] = func(x int) int { return x + 200 }
    fmt.Println(m["first"](100))
}

// 4
// 102
// 300

2. 闭包

闭包 = 函数 + 环境变量

光看上面的话,我们也不知道具体什么意思;其实记住下面两点就行:

  1. 匿名函数能获取外部变量的值
package main

import "fmt"

func main() {
    x := 2
    func() {
        fmt.Println(x) // 能获取外部的x
    }()
}
  1. 外部变量的会以地址(引用)方式的方式绑定

例子1:通过地址值验证(打印出来是同一个地址)

package main

import "fmt"

func main() {
    x := 1
    f := func() {
        fmt.Printf("f中x地址: %p\n", &x)
        fmt.Println(x) // 能获取外部的x
    }

    fmt.Printf("x地址: %p\n", &x)
    f()
}

// x地址: 0xc00001a198
// f中x地址: 0xc00001a198
// 1

例子2: 在匿名函数中修改值

package main

import "fmt"

func main() {
    f := genFuc()

    // 同一个匿名函数 修改的是同一个x地址 所以x会变
    f() // 打印 1
    f() // 打印 2
    f() // 打印 3

    // 这个时候返回的是 新匿名函数 x地址不同 所以回到初识值了
    f1 := genFuc()
    f1() // 打印 1
}

// 返回一个匿名函数
func genFuc() func() {
    x := 0
    return func() {
        x++
        fmt.Println(x)
    }
}

// 1
// 2
// 3
// 1

3. 循环中变量引起的问题

循环指的是for/range,我们先来看产生的问题

package main

import "fmt"

func main() {
    ch := make(chan func(), 10) // 这个通道中装的是函数

    // 装入通道
    for i := 0; i < 10; i++ {
        ch <- func() {
            fmt.Println(i) // 绑定外部变量i
        }
    }

    close(ch)

    // 取出函数后执行
    for f := range ch {
        f()
    }
}

// 10
// 10
// 10
// 10
// 10
// 10
// 10
// 10
// 10
// 10

我们会发现输出的居然全是10;为什么会这样呢?

在循环语句中的变量,它只初始化了一次,它的地址是不变的;每次改动的只是将不同的值分配到这个地址上而已;
而匿名函数绑定的是变量的地址,在绑定变量后,函数没有立即执行,而等到执行时,地址i中的值早已变成10了。

这种情况,发生在延迟执行(绑定变量后,执行前变量值发生了更改)。

如何避免呢?
在每一轮循环下增加一行,初始化一个变量用于存储绑定值即可。

修改后代码如下:

package main

import "fmt"

func main() {
    ch := make(chan func(), 10) // 这个通道中装的是函数

    // 装入通道
    for i := 0; i < 10; i++ {
        ni := i
        ch <- func() {
            fmt.Println(ni) // 绑定外部变量i
        }
    }

    close(ch)

    // 取出函数后执行
    for f := range ch {
        f()
    }
}

// 0
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9

相关文章

  • Golang基础(五)——函数二

    Golang基础(五)——函数二 @([07] golang)[Go总结] 匿名函数 匿名函数就是将一个函数直接赋...

  • Go中的函数

    在Golang中函数有包内的函数,有包外的函数,还有闭包函数(匿名函数) 包内函数是以小写字母开头的,包外函数是以...

  • Golang理解 匿名函数

    匿名函数 匿名函数(英语:Anonymous Function)在计算机编程中是指一类无需定义标识符(函数名)的函...

  • 胡扯JS系列-匿名函数的自动运行

    函数有很多种,我们就选择我们不懂的函数开始学习! JS中自动运行的匿名函数 在JavaScript中可以使用匿名函...

  • 备孕?看这篇就够啦!

    结婚是人生大事!无论你是准备结婚还是刚刚结婚,都会幻想过将来宝宝的名字吧,ta长什么样子?跟谁更像呢?身高随爸爸还...

  • arguments.callee用法

    argument.callee 在那个函数中运行,他就代表哪一个函数。一般用在匿名函数中。在匿名函数中有时候需要自...

  • 作用链和闭包

    一、匿名函数 1.1 匿名函数的概念 ​ 声明一个没有函数名的函数,就是匿名函数。 ​ 有函数名的函数就...

  • 箭头函数笔记

    回顾ES3,5 上面代码中示例匿名函数,可以拆分成三步看。 声明一个变量let fn 声明一个匿名函数。 将匿名函...

  • C++11新特性--lambda

    匿名函数--lambda函数     匿名函数或者匿名类这种语法在其他语言(如lisp,java中)早有应用。在C...

  • 13.Python编程:lambda表达式(匿名函数)

    前面学习了Python中的函数,本文学习一下匿名函数。Python 使用 lambda 来创建匿名函数。所谓匿名,...

网友评论

      本文标题:golang中匿名函数看这篇就够啦

      本文链接:https://www.haomeiwen.com/subject/kmbdwdtx.html