Golang匿名函数的使用示例与代码分享

Golang匿名函数的使用示例与代码分享 https://play.golang.org/p/wTKHFo8ryvQ

11 回复

非常有趣!而且很有帮助!

更多关于Golang匿名函数的使用示例与代码分享的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


谢谢!那么作用域和主体是同义词吗?

明白了!非常感谢!这真的让我豁然开朗,而且我热爱学习。

抱歉,我还没完成就按了发送按钮。在上面的代码中,所有函数都是匿名函数吗?或者哪些是匿名函数?

正在处理上述问题…
“在我们重新声明后,它会遮蔽外部变量”
我不明白这是什么意思。具体来说,"遮蔽"指的是什么

[!quote] iegomez 代码块与标识符作用域 - Go 101

这篇文章非常有趣,我已经将其添加至书签。

我也在阅读语言规范。

https://golang.org/ref/spec#Function_literals

在"func(a, b int, z float64) bool { return ab < int(z) }“中,”(a, b int, z float64) bool { return ab < int(z) }"是函数体吗?

func(a, b int, z float64) bool { return a*b < int(z) }

这意味着我们在外部作用域声明的 a 变量,只要我们不重新声明它,就可以在内部作用域中访问。我们能够重新声明它(而不仅仅是赋值),是因为我们处于局部内部作用域中,就像我们可以在局部函数作用域中重新声明全局变量一样。

因此,一旦我们声明了内部的 a 变量,它将在该作用域中有效地遮蔽外部的 a 名称,这意味着它仅在该作用域内局部可见,你将失去对外部变量的可见性,并且对它的任何更改都将保持局部性。这就是为什么在内部作用域结束后,如果我们打印 a 的值,仍然会看到原始外部作用域的值 1,因为内部声明遮蔽了原始声明,因此没有影响它。

这些是匿名函数:

func() {
		fmt.Println("Anonymous func ran")
	}()

	func(x int) {
		fmt.Println("The meaning of life:", x)
	}(42)

另一方面,foo 不是匿名函数,Println(来自 fmt 包的函数)和 main(同样是一个命名函数)也都不是匿名函数,因为它们都有标识符。当函数声明时没有标识符,它们就是匿名函数。

cherilexvold1974: 在" func(a, b int, z float64) bool { return a b < int(z) }“中,”(a, b int, z float64) bool { return a b < int(z) }"是函数体吗?

不,函数体是组成函数的语句,即函数开括号和闭括号之间的内容。也就是:

return a*b < int(z)

不,它们并不相同。通过以下示例及其注释来说明:

func myFunc() {
	//这是函数体的开始
	//也是函数作用域(我们称之为FSC)的开始
	a := 1
	fmt.Println(a) //这里会输出1
	{
		//这里仍然是函数体的一部分
		//这也是内部作用域(我们称之为ISC1)的开始
		//我们可以在这里重新声明a,它会在重新声明后遮蔽外层的a,但在重新声明前仍能访问原始的a
		fmt.Println(a) //仍然输出1
		a := 2         //现在在这个作用域内,它遮蔽了原始的a
		b := 3         //变量b仅在此作用域内声明,因此即使这是函数体的一部分,也不能在外部使用它
		fmt.Println(a) //现在输出2
		fmt.Println(b) //这里输出3
		//ISC1作用域在此结束
	}
        //这里仍然是函数体的一部分
	//这里无法访问b,因此调用fmt.Println(b)将无法编译。可以取消下一行的注释来尝试
	//fmt.Println(b)
	{
		//这里仍然是函数体的一部分
		//这是另一个内部作用域(我们称之为ISC2)的开始
		//这里的a仍然是1,因为重新声明仅在ISC1作用域内可见
		fmt.Println(a) //仍然输出1
		//同样,这里无法访问b,因为它未在此作用域或外部FSC作用域中声明
		//因此这里调用fmt.Println(b)将无法编译。可以取消下一行的注释来尝试
		//fmt.Println(b)
		//ISC2作用域在此结束
	}
	//正如预期,a仍然是1,而b在此不存在
	fmt.Println(a) //仍然输出1
	//fmt.Println(b)
	//现在函数作用域FSC和函数体都结束了
}

你可以在Go Playground上尝试:https://play.golang.org/p/BdVEwlZ6OJk。

因此,函数体包含函数中的所有语句,即大括号之间的所有内容,这本身也是一个作用域。但函数体和作用域并不相同,因为在一个函数体中可能包含多个作用域,而且也存在比函数体更大的作用域(例如,在包作用域中声明的变量对该包中的所有函数都可见)。除了这些之外还有更多作用域,比如文件作用域或属于控制流(iffor等)的局部作用域等等。你可以在这里阅读更多关于作用域的内容:https://go101.org/article/blocks-and-scopes.html。

现在,这可能信息量有点大,但你至少应该阅读一些关于这些概念的内容,以便开始区分它们并继续前进。

在Go语言中,匿名函数是一种没有名称的函数,可以直接定义和使用,常用于实现闭包、回调或临时函数逻辑。根据您提供的Playground链接,我假设您想了解匿名函数的基本用法和示例。以下是一个详细的代码示例,展示匿名函数的定义、调用以及常见应用场景。

示例代码:匿名函数的基本使用

package main

import "fmt"

func main() {
    // 示例1:定义并立即调用匿名函数
    func() {
        fmt.Println("这是一个立即执行的匿名函数")
    }() // 注意:末尾的括号表示立即调用

    // 示例2:将匿名函数赋值给变量,然后调用
    greet := func(name string) {
        fmt.Printf("Hello, %s!\n", name)
    }
    greet("Alice") // 输出: Hello, Alice!

    // 示例3:匿名函数作为参数传递给其他函数(例如高阶函数)
    numbers := []int{1, 2, 3, 4, 5}
    // 使用匿名函数定义过滤逻辑
    evenNumbers := filter(numbers, func(n int) bool {
        return n%2 == 0
    })
    fmt.Println("偶数:", evenNumbers) // 输出: 偶数: [2 4]

    // 示例4:匿名函数实现闭包,捕获外部变量
    counter := createCounter()
    fmt.Println(counter()) // 输出: 1
    fmt.Println(counter()) // 输出: 2
}

// filter 函数:接受一个切片和一个匿名函数作为参数,返回过滤后的切片
func filter(nums []int, condition func(int) bool) []int {
    var result []int
    for _, num := range nums {
        if condition(num) {
            result = append(result, num)
        }
    }
    return result
}

// createCounter 函数:返回一个匿名函数,该函数形成闭包,捕获外部变量 count
func createCounter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

代码解释:

  1. 立即调用匿名函数:通过 func() { ... }() 定义并直接执行,无需赋值。
  2. 变量赋值:将匿名函数赋给变量 greet,然后像普通函数一样调用。
  3. 作为参数传递:在 filter 函数中,匿名函数定义了过滤条件,用于处理切片元素。
  4. 闭包应用createCounter 返回一个匿名函数,该函数捕获并修改外部变量 count,实现状态保持。

运行结果:

执行上述代码,输出如下:

这是一个立即执行的匿名函数
Hello, Alice!
偶数: [2 4]
1
2

匿名函数在Go中非常灵活,常用于并发编程(如goroutine)、延迟执行(defer)等场景。如果您有具体问题或需要更多示例,请提供Playground中的代码细节,我可以进一步分析。

回到顶部