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错误时,在程序出现宕机之前被执行,依次来恢复程序。

相关文章
|
27天前
|
中间件 Go API
Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架
本文概述了Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架。
70 1
|
28天前
|
数据库连接 Go 数据库
Go语言中的错误注入与防御编程。错误注入通过模拟网络故障、数据库错误等,测试系统稳定性
本文探讨了Go语言中的错误注入与防御编程。错误注入通过模拟网络故障、数据库错误等,测试系统稳定性;防御编程则强调在编码时考虑各种错误情况,确保程序健壮性。文章详细介绍了这两种技术在Go语言中的实现方法及其重要性,旨在提升软件质量和可靠性。
29 1
|
1月前
|
数据采集 监控 Java
go语言编程学习
【11月更文挑战第3天】
41 7
|
1月前
|
缓存 前端开发 中间件
go语言中Web框架
【10月更文挑战第22天】
44 4
|
1月前
|
Unix Linux Go
go进阶编程:Golang中的文件与文件夹操作指南
本文详细介绍了Golang中文件与文件夹的基本操作,包括读取、写入、创建、删除和遍历等。通过示例代码展示了如何使用`os`和`io/ioutil`包进行文件操作,并强调了错误处理、权限控制和路径问题的重要性。适合初学者和有经验的开发者参考。
|
1月前
|
JSON 安全 网络协议
go语言使用内置函数和标准库
【10月更文挑战第18天】
19 3
|
2月前
|
Java 大数据 Go
Go语言:高效并发的编程新星
【10月更文挑战第21】Go语言:高效并发的编程新星
53 7
|
2月前
|
Go 数据处理 调度
Go语言中的并发模型:解锁高效并行编程的秘诀
本文将探讨Go语言中独特的并发模型及其在现代软件开发中的应用。通过深入分析 Goroutines 和 Channels,我们将揭示这一模型如何简化并行编程,提升应用性能,并改变开发者处理并发任务的方式。不同于传统多线程编程,Go的并发方法以其简洁性和高效性脱颖而出,为开发者提供了一种全新的编程范式。
|
3月前
|
数据库 开发者 Python
实战指南:用Python协程与异步函数优化高性能Web应用
在快速发展的Web开发领域,高性能与高效响应是衡量应用质量的重要标准。随着Python在Web开发中的广泛应用,如何利用Python的协程(Coroutine)与异步函数(Async Functions)特性来优化Web应用的性能,成为了许多开发者关注的焦点。本文将从实战角度出发,通过具体案例展示如何运用这些技术来提升Web应用的响应速度和吞吐量。
34 1
|
3月前
|
存储 缓存 Go
go语言编程系列(五)
go语言编程系列(五)