深入理解 Go 语言的一等函数及其应用(中)

简介: 任何一门编程语言都离不开函数,无论是命令式语言 C、多范式编程语言 C++,还是面向对象编程语言 Java、Ruby,动态语言 Python、JavaScript,函数这一语法元素都是当仁不让的核心。

高阶函数

对高阶函数的定义是这个函数至少做到以下的某一项的功能:


  • 以一个或者多个函数作为参数
  • 返回一个函数作为其结果

将函数作为参数传递给其他函数

package main
import (
    "fmt"
)
func simple(a func(a, b int) int) {
    fmt.Println(a(60, 7))
}
func main() {
    f := func(a, b int) int {
        return a + b
    }
    simple(f)
}


我们定义一个函数 simple 函数,它接收两个 int 参数,并返回一个 int 参数,然后把匿名函数传给变量 f,然后把 f 作为参数传递给 simple 函数,最终这个程序将打印 67 输出:

67

从其他函数中返回函数

现在让我们重写上面的程序,从 simple 函数中返回一个函数:

package main
import (
    "fmt"
)
func simple() func(a, b int) int {
    f := func(a, b int) int {
        return a + b
    }
    return f
}
func main() {
    s := simple()
    fmt.Println(s(2022, 60))
}


运行该程序,得到结果;

2082

闭包

闭包是匿名函数的一种特殊情况。闭包是匿名函数,它访问定义在函数主体之外的变量。


代码如下:

package main
import (
    "fmt"
)
func main() {
    a := 2022
    func() {
        fmt.Println("a = ", a)
    }()
}


每个闭包都与它自己周围的变量绑定。让我们通过一个简单的例子来理解这意味着什么。

package main
import (  
    "fmt"
)
func appendStr() func(string) string {  
    t := "Hello"
    c := func(b string) string {
        t = t + " " + b
        return t
    }
    return c
}
func main() {  
    a := appendStr()
    b := appendStr()
    fmt.Println(a("World"))
    fmt.Println(b("Everyone"))
    fmt.Println(a("Gopher"))
    fmt.Println(b("!"))
}


在上面的程序中,appendStr 函数返回一个闭包。这个闭包被绑定到变量 t 上,变量 ab 是闭包,被绑定到它们自己的值 t 上。


我们传递参数 World  给 a,然后 a 的值变成了 Hello World


传递参数 Everyone 给 b,然后 b 的值变成了 Hello Everyone

Hello World  
Hello Everyone  
Hello World Gopher  
Hello Everyone !  

闭包通常也是支持嵌套和 defer 工作的方法。在下面的例子中,我们可以看到一个允许我们嵌套工作的函数闭包:

package main
import (
  "fmt"
  "sort"
)
func main() {
  input := []string{"foo", "bar", "baz"}
  var result []string
  // closure callback
  func() {
    result = append(input, "abc")
    result = append(result, "def")
    sort.Sort(sort.StringSlice(result))
  }()
  fmt.Println(result)
}


运行结果:

[abc bar baz def foo]


相关文章
|
5天前
|
数据采集 存储 Go
使用Go语言和chromedp库下载Instagram图片:简易指南
Go语言爬虫示例使用chromedp库下载Instagram图片,关键步骤包括设置代理IP、创建带代理的浏览器上下文及执行任务,如导航至用户页面、截图并存储图片。代码中新增`analyzeAndStoreImage`函数对图片进行分析和分类后存储。注意Instagram的反爬策略可能需要代码适时调整。
使用Go语言和chromedp库下载Instagram图片:简易指南
|
22小时前
|
程序员 Go
Golang深入浅出之-Select语句在Go并发编程中的应用
【4月更文挑战第23天】Go语言中的`select`语句是并发编程的关键,用于协调多个通道的读写。它会阻塞直到某个通道操作可行,执行对应的代码块。常见问题包括忘记初始化通道、死锁和忽视`default`分支。要解决这些问题,需确保通道初始化、避免死锁并添加`default`分支以处理无数据可用的情况。理解并妥善处理这些问题能帮助编写更高效、健壮的并发程序。结合使用`context.Context`和定时器等工具,可提升`select`的灵活性和可控性。
8 2
|
1天前
|
安全 Go 开发者
Golang深入浅出之-Go语言并发编程面试:Goroutine简介与创建
【4月更文挑战第22天】Go语言的Goroutine是其并发模型的核心,是一种轻量级线程,能低成本创建和销毁,支持并发和并行执行。创建Goroutine使用`go`关键字,如`go sayHello("Alice")`。常见问题包括忘记使用`go`关键字、不正确处理通道同步和关闭、以及Goroutine泄漏。解决方法包括确保使用`go`启动函数、在发送完数据后关闭通道、设置Goroutine退出条件。理解并掌握这些能帮助开发者编写高效、安全的并发程序。
10 1
|
1天前
|
人工智能 Go 调度
掌握Go并发:Go语言并发编程深度解析
掌握Go并发:Go语言并发编程深度解析
|
1天前
|
SQL 关系型数据库 MySQL
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
|
2天前
|
Go 开发者
Golang深入浅出之-Go语言流程控制:if、switch、for循环详解
【4月更文挑战第21天】本文介绍了Go语言中的流程控制语句,包括`if`、`switch`和`for`循环。`if`语句支持简洁的语法和初始化语句,但需注意比较运算符的使用。`switch`语句提供多分支匹配,可省略`break`,同时支持不带表达式的形式。`for`循环有多种形式,如基本循环和`for-range`遍历,遍历时修改原集合可能导致未定义行为。理解并避免易错点能提高代码质量和稳定性。通过实践代码示例,可以更好地掌握Go语言的流程控制。
11 3
Golang深入浅出之-Go语言流程控制:if、switch、for循环详解
|
2天前
|
Go
Golang深入浅出之-Go语言函数基础:定义、调用与多返回值
【4月更文挑战第21天】Go语言函数是代码组织的基本单元,用于封装可重用逻辑。本文介绍了函数定义(包括基本形式、命名、参数列表和多返回值)、调用以及匿名函数与闭包。在函数定义时,注意参数命名和注释,避免参数顺序混淆。在调用时,要检查并处理多返回值中的错误。理解闭包原理,小心处理外部变量引用,以提升代码质量和可维护性。通过实践和示例,能更好地掌握Go语言函数。
17 1
Golang深入浅出之-Go语言函数基础:定义、调用与多返回值
|
3天前
|
程序员 Go API
【Go语言快速上手(二)】 分支与循环&函数讲解
【Go语言快速上手(二)】 分支与循环&函数讲解
|
3天前
|
Go
Golang深入浅出之-Go语言基础语法:变量声明与赋值
【4月更文挑战第20天】本文介绍了Go语言中变量声明与赋值的基础知识,包括使用`var`关键字和简短声明`:=`的方式,以及多变量声明与赋值。强调了变量作用域、遮蔽、初始化与零值的重要性,并提醒读者注意类型推断时的一致性。了解这些概念有助于避免常见错误,提高编程技能和面试表现。
19 0
|
3天前
|
编译器 Go 开发者
Go语言入门|包、关键字和标识符
Go语言入门|包、关键字和标识符
22 0