【Go】匿名函数与闭包

目录

一、匿名函数

基础介绍

形式

[示例程序 1: 直接调用](#示例程序 1: 直接调用)

[示例程序 2: 作为变量赋值](#示例程序 2: 作为变量赋值)

[示例程序 3: 作为函数参数](#示例程序 3: 作为函数参数)

[示例程序 4: 使用匿名函数进行排序](#示例程序 4: 使用匿名函数进行排序)

[示例程序 5: 匿名函数用于延迟执行](#示例程序 5: 匿名函数用于延迟执行)

[示例程序 6: 通过匿名函数实现迭代器](#示例程序 6: 通过匿名函数实现迭代器)

二、闭包用法

基础知识

[示例程序 1: 状态保持器](#示例程序 1: 状态保持器)

[示例程序 2: 生成器函数](#示例程序 2: 生成器函数)

[示例程序 3: 事件处理](#示例程序 3: 事件处理)

[示例程序 4: 资源清理](#示例程序 4: 资源清理)


一、匿名函数

在Go语言中,匿名函数是没有名字的函数,可以在需要的地方直接定义和使用。匿名函数的一个重要用途是实现闭包。在Go中,匿名函数可以被赋值给变量,作为参数传递,或直接在其它函数内调用。这提供了极大的灵活性和代码的简洁性。下面,我将介绍匿名函数的基本概念,并提供三个示例程序来展示其使用方法。

基础介绍

形式

匿名函数通常定义的形式是:

Go 复制代码
func(参数列表) 返回类型 {
    // 函数体
}

可以将其赋值给一个变量,或者直接在需要的地方调用。

示例程序 1: 直接调用

这个示例展示了如何直接调用一个匿名函数,无需先赋值给变量。

Go 复制代码
package main

import "fmt"

func main() {
    // 直接定义并调用匿名函数
    func(msg string) {
        fmt.Println(msg)
    }("Hello, Go!")
}

在这个例子中,匿名函数被直接调用,并传递了一个字符串参数。

示例程序 2: 作为变量赋值

这个示例展示了如何将匿名函数赋值给变量,并在后续调用这个变量。

Go 复制代码
package main

import "fmt"

func main() {
    // 将匿名函数赋值给变量 greet
    greet := func(name string) {
        fmt.Printf("Hello, %s!\n", name)
    }

    // 调用函数
    greet("World")
    greet("Go")
}

这里,匿名函数赋值给变量 greet,然后通过变量名调用该函数。

示例程序 3: 作为函数参数

匿名函数可以作为参数传递给其他函数。这是在Go语言中实现回调或者定制行为的一种常用方式。

Go 复制代码
package main

import "fmt"

// 定义一个函数,接受另一个函数作为参数
func process(f func(string), value string) {
    f(value)
}

func main() {
    // 调用 process,传递匿名函数和字符串参数
    process(func(s string) {
        fmt.Println(s)
    }, "Go is fun!")
}

在这个例子中,process 函数接受一个函数作为参数。我们传递了一个匿名函数,它接受一个字符串参数并打印它。

示例程序 4: 使用匿名函数进行排序

Go的sort.Slice函数允许使用匿名函数来定义排序逻辑。这是匿名函数作为功能参数的一个常见应用。

Go 复制代码
package main

import (
    "fmt"
    "sort"
)

func main() {
    people := []struct {
        Name string
        Age  int
    }{
        {"Alice", 23},
        {"Eve", 2},
        {"Bob", 25},
    }

    // 使用匿名函数进行排序,按年龄排序
    sort.Slice(people, func(i, j int) bool {
        return people[i].Age < people[j].Age
    })

    fmt.Println("Sorted by age:", people)
}

示例程序 5: 匿名函数用于延迟执行

在Go中,defer语句常与匿名函数一起使用,以确保在函数返回前执行某些清理工作。

Go 复制代码
package main

import "fmt"

func main() {
    // 使用 defer 语句调用匿名函数
    defer func() {
        fmt.Println("Cleaning up!")
    }()

    fmt.Println("Doing some work...")
    // 当 main 函数返回时,会执行匿名函数中的打印语句
}

这个示例展示了如何使用匿名函数进行资源清理或执行其他结束工作,这些工作会在当前函数结束时自动执行。

示例程序 6: 通过匿名函数实现迭代器

匿名函数可以用来创建一个简单的迭代器,封装特定的迭代逻辑。

Go 复制代码
package main

import "fmt"

func newCounter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

func main() {
    counter := newCounter()

    fmt.Println(counter()) // 输出 1
    fmt.Println(counter()) // 输出 2
    fmt.Println(counter()) // 输出 3

    // 创建另一个独立的计数器
    anotherCounter := newCounter()
    fmt.Println(anotherCounter()) // 输出 1
}

在这个例子中,每次调用newCounter都会创建一个新的闭包,这个闭包维护自己的count状态,独立于其他闭包。

二、闭包用法

Go语言中,闭包是一种函数,能够引用在其外部作用域定义的变量。由于闭包可以访问并操作这些变量,即使在它们的原始作用域已经结束后,它们被广泛用于创建具有私有状态的函数、实现回调函数和迭代器等。下面我将详细解释Go中闭包的基础知识,并提供几个实际项目中可能用到的示例。

基础知识

在Go中,闭包通常是在一个函数内部创建的匿名函数,这个匿名函数访问外部函数的局部变量。这些变量随着匿名函数的存在而持续存在,即使外部函数的执行已经结束。

示例程序 1: 状态保持器

使用闭包实现一个简单的状态保持器,这可以在需要对状态进行封装和管理时非常有用。

Go 复制代码
package main

import "fmt"

func stateHolder(initial int) func() int {
    state := initial
    return func() int {
        state++
        return state
    }
}

func main() {
    counter := stateHolder(10)
    fmt.Println(counter()) // 输出 11
    fmt.Println(counter()) // 输出 12

    anotherCounter := stateHolder(20)
    fmt.Println(anotherCounter()) // 输出 21
    fmt.Println(anotherCounter()) // 输出 22
}

在这个例子中,每个闭包都保持了自己的状态,互不影响。

示例程序 2: 生成器函数

闭包可以用来创建生成器,例如生成连续的斐波那契数列。

Go 复制代码
package main

import "fmt"

func fibonacci() func() int {
    a, b := 0, 1
    return func() int {
        ret := a
        a, b = b, a+b
        return ret
    }
}

func main() {
    fib := fibonacci()
    for i := 0; i < 10; i++ {
        fmt.Println(fib())
    }
}

这个生成器函数每次被调用时,都会返回序列中的下一个斐波那契数。

示例程序 3: 事件处理

闭包可以用来处理事件或回调,使得状态和逻辑封装在一个单独的函数中。

Go 复制代码
package main

import "fmt"

type Button struct {
    onClick func()
}

func NewButton() *Button {
    return &Button{onClick: func() {}}
}

func main() {
    button := NewButton()
    count := 0
    button.onClick = func() {
        count++
        fmt.Printf("Button clicked %d times\n", count)
    }

    // 模拟点击事件
    button.onClick()
    button.onClick()
    button.onClick()
}

这个示例中的闭包捕获了点击计数,并在每次点击时更新。

示例程序 4: 资源清理

利用闭包在函数结束时进行资源清理。

Go 复制代码
package main

import "fmt"

func cleanup(resource string) func() {
    return func() {
        fmt.Printf("Cleaning up %s\n", resource)
    }
}

func main() {
    defer cleanup("resourceA")()
    fmt.Println("Doing some work with resourceA")
}
相关推荐
NiNg_1_2341 分钟前
Vue3 Pinia持久化存储
开发语言·javascript·ecmascript
带带老表学爬虫10 分钟前
java数据类型转换和注释
java·开发语言
qianbo_insist12 分钟前
simple c++ 无锁队列
开发语言·c++
千里码aicood17 分钟前
【2025】springboot教学评价管理系统(源码+文档+调试+答疑)
java·spring boot·后端·教学管理系统
BigYe程普23 分钟前
我开发了一个出海全栈SaaS工具,还写了一套全栈开发教程
开发语言·前端·chrome·chatgpt·reactjs·个人开发
彭于晏68925 分钟前
Android广播
android·java·开发语言
程序员-珍43 分钟前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发
弱冠少年1 小时前
websockets库使用(基于Python)
开发语言·python·numpy
长天一色1 小时前
C语言日志类库 zlog 使用指南(第五章 配置文件)
c语言·开发语言
liuxin334455661 小时前
教育技术革新:SpringBoot在线教育系统开发
数据库·spring boot·后端