【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")
}
相关推荐
众拾达人14 分钟前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言
皓木.16 分钟前
Mybatis-Plus
java·开发语言
不良人天码星16 分钟前
lombok插件不生效
java·开发语言·intellij-idea
源码哥_博纳软云39 分钟前
JAVA同城服务场馆门店预约系统支持H5小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台
学会沉淀。1 小时前
Docker学习
java·开发语言·学习
追逐时光者1 小时前
免费、简单、直观的数据库设计工具和 SQL 生成器
后端·mysql
西猫雷婶1 小时前
python学opencv|读取图像(二十一)使用cv2.circle()绘制圆形进阶
开发语言·python·opencv
kiiila1 小时前
【Qt】对象树(生命周期管理)和字符集(cout打印乱码问题)
开发语言·qt
初晴~1 小时前
【Redis分布式锁】高并发场景下秒杀业务的实现思路(集群模式)
java·数据库·redis·分布式·后端·spring·