Go Web编程实战(4)----函数(二)

简介: Go Web编程实战(4)----函数(二)

匿名函数


匿名函数被称为“闭包”,是指一类无需定义的标识符(函数名)的函数或子程序。匿名函数没有函数名,只有函数体。函数可以作为一种被赋值给函数类型的变量;匿名函数往往以变量方式被传递。


匿名函数的定义

匿名函数的定义可以被理解为没有名字的函数,其定义与使用方式如下:

//定义
func (参数列表)(返回值列表){
  //函数体
}
//使用方式
func main() {
  x, y := 3, 9
  defer func(a int) {
  fmt.Println(a, y) //y为闭包引用
  }(x)
  x += 10
  y += 100
  fmt.Println(x, y)
}


运行之后,输出如下:


运行上面的代码,读者肯定会发现,先打印的是最后一条输出语句,然后才打印func输出,因为defer是延迟语句。而defer设计就是为了在函数执行完毕后,及时的释放资源而设计的。(最后单独讲解)


而且上面匿名函数是一个“内联”语句。匿名函数的优越性在于,可以直接使用函数内的变量而不必声明。


匿名函数的调用

下面,我们将匿名函数赋值给变量,把函数当变量使用起来。示例如下:

func main() {
  x, y := 3, 9
  f := func(x, y int) {
  fmt.Println(x + y)
  }
  f(x, y)
}


回调函数

回调函数,即Callback,被主函数调用运算后会返回主函数。也就是通过函数参数传递到其他代码的某一块可执行代码的引用。


匿名函数作为回调函数使用,在Go语言中非常常见。比如,可以使用匿名函数作为参数,来实现对切片中的元素遍历操作,示例如下:

func TraversalPrint(list []int, f func(int)) {
  for _, value := range list {
  f(value)
  }
}
func main() {
  slice := []int{1, 2, 3, 4, 5}
  TraversalPrint(slice, func(value int) {
  fmt.Println(value)
  })
}


运行之后,效果如下:



defer延迟语句


在前面,我们简单的介绍了一下defer。它是为了在函数执行完毕后及时的释放资源而设计的。其具体的逻辑如下:


1.当程序执行到一个defer时,不会立即执行defer后的语句,而是将defer后的语句压入一个专门存储defer语句的栈中,然后继续执行函数下一个语句。

2.当函数执行完毕后,再从defer栈中依次从栈顶取出语句执行(栈的规则是先进后出,也就是最先进去的最后执行)

3.在defer将语句放入栈时,也会将相关的值复制进入栈中。所以,上面的a输出的是x的最开始的值。


示例如下:

func deferCall()  {
  defer func1()
  defer func2()
  defer func3()
}
func func1()  {
  fmt.Println("1")
}
func func2()  {
  fmt.Println("2")
}
func func3()  {
  fmt.Println("3")
}
func main() {
  deferCall()
}


运行之后,你会发现它会输出3,2,1,这也就是栈的先进后出。


defer与return的执行顺序

假如一个函数体中,即出现了defer,也出现了return返回值,那它的先后顺序是怎样的呢?下面,我们来通过一段代码进行观察,示例如下:

var name string="liyuanjing"
func func1() string {
  defer func() {
  name="fengxinyao"
  }()
  fmt.Println(name)
  return name
}
func main() {
  func1 :=func1()
  fmt.Println(name)
  fmt.Println(func1)
}


运行之后,效果如下:


运行结果分析:


1.在主main()函数中,开始只是将函数赋值给一个变量,并没有指定函数,所以第一次输出肯定原始的name值“liyunajing”。

2.当调用函数后,在defer里改变了全局变量,此时的name的值已经变为"fengxinyao"。

3.那为什么最后输出还是“liyuanjing”呢?解释只有一个,即defer是在return后才调用的。所以在执行defer前,func1已经被赋值成了“liyuanjing”。


defer常用场景

除了释放资源之外,defer还有一个应用场景,那就是与recover()函数一起使用。


当程序出现宕机或者遇到panic错误时,recover()函数可以恢复执行,而且不会报告宕机错误。之前说过,defer不但可以在return返回前调用,也可以在程序宕机显示panic错误时,在程序出现宕机之前被执行,依次来恢复程序。

相关文章
|
1月前
|
存储 人工智能 Go
Go-Zero全流程实战即时通讯
Go-Zero 是一个功能丰富的微服务框架,适用于开发高性能的即时通讯应用。它具备中间件、工具库和代码生成器,简化开发流程。本文介绍其环境搭建、项目初始化及即时通讯功能实现,涵盖用户认证、消息收发和实时推送,帮助开发者快速上手。
164 0
|
1月前
|
数据采集 Go API
Go语言实战案例:多协程并发下载网页内容
本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。
|
1月前
|
Go 开发者
Go语言实战案例:使用select监听多个channel
本文为《Go语言100个实战案例 · 网络与并发篇》第5篇,详解Go并发核心工具`select`的使用。通过实际案例讲解如何监听多个Channel、实现多任务处理、超时控制和非阻塞通信,帮助开发者掌握Go并发编程中的多路异步事件处理技巧。
|
1月前
|
数据采集 编解码 监控
Go语言实战案例:使用channel实现生产者消费者模型
本文是「Go语言100个实战案例 · 网络与并发篇」第4篇,通过实战案例详解使用 Channel 实现生产者-消费者模型,涵盖并发控制、任务调度及Go语言并发哲学,助你掌握优雅的并发编程技巧。
|
1月前
|
数据采集 消息中间件 编解码
Go语言实战案例:使用 Goroutine 并发打印
本文通过简单案例讲解 Go 语言核心并发模型 Goroutine,涵盖协程启动、输出控制、主程序退出机制,并结合 sync.WaitGroup 实现并发任务同步,帮助理解 Go 并发设计思想与实际应用。
|
1月前
|
数据采集 JSON Go
Go语言实战案例:实现HTTP客户端请求并解析响应
本文是 Go 网络与并发实战系列的第 2 篇,详细介绍如何使用 Go 构建 HTTP 客户端,涵盖请求发送、响应解析、错误处理、Header 与 Body 提取等流程,并通过实战代码演示如何并发请求多个 URL,适合希望掌握 Go 网络编程基础的开发者。
|
2月前
|
JSON 前端开发 Go
Go语言实战:创建一个简单的 HTTP 服务器
本篇是《Go语言101实战》系列之一,讲解如何使用Go构建基础HTTP服务器。涵盖Go语言并发优势、HTTP服务搭建、路由处理、日志记录及测试方法,助你掌握高性能Web服务开发核心技能。
|
2月前
|
存储 算法 数据可视化
Go语言实战:图的邻接表表示法实现详解
本文是《Go语言100个实战案例》系列之一,讲解图的邻接表表示法及其在Go语言中的实现。适用于稀疏图,节省空间,适合初学者与进阶开发者学习图结构在工程中的应用。
|
2月前
|
机器学习/深度学习 存储 算法
Go语言实战案例-广度优先遍历BFS
广度优先遍历(BFS)是一种层级展开的搜索策略,常用于树与图的遍历、最短路径查找、二维数组中的感染扩散等问题。它借助队列实现,优先访问当前层所有节点,再进入下一层,适用于寻找最短路径、层序遍历、岛屿问题等场景。
|
2月前
|
算法 Go C++
Go语言实战案例-深度优先遍历DFS
深度优先遍历(DFS)是一种用于遍历图和树结构的重要算法,其核心思想是“一条路走到底”,即沿着每个分支尽可能深入,直到无法继续再回溯。在树中,DFS包括前序、中序和后序三种遍历方式;在图中,DFS可用于寻找路径、计算连通分量、拓扑排序等。该算法通常通过递归或栈实现,适用于解决岛屿数量、迷宫路径、括号生成等经典问题。本文还对比了DFS与BFS的区别,并介绍了其在不同场景下的应用与实现方法。

热门文章

最新文章