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

相关文章
|
5天前
|
Java 应用服务中间件 测试技术
深入探索Spring Boot Web应用源码及实战应用
【5月更文挑战第11天】本文将详细解析Spring Boot Web应用的源码架构,并通过一个实际案例,展示如何构建一个基于Spring Boot的Web应用。本文旨在帮助读者更好地理解Spring Boot的内部工作机制,以及如何利用这些机制优化自己的Web应用开发。
31 3
|
1天前
|
缓存 监控 安全
Django框架在大型Web应用中的架构设计与实战
【5月更文挑战第18天】Django框架在构建大型Web应用中扮演重要角色,采用分层架构(数据、业务逻辑、表示层)和多应用组织模式,结合缓存策略(如Memcached、Redis)提升性能。通过异步处理、分布式部署提高响应速度和扩展性。关注数据分区、安全设计及监控日志,确保系统高效、稳定。Django为复杂业务提供坚实基础,助力打造卓越Web系统。
18 7
|
2天前
|
JSON JavaScript 前端开发
web前端入门到实战:32道常见的js面试题,2024年最新秋招是直接面试吗
web前端入门到实战:32道常见的js面试题,2024年最新秋招是直接面试吗
|
2天前
|
JavaScript 前端开发 程序员
web前端入门到实战:32道常见的js面试题(1),面试哪些
web前端入门到实战:32道常见的js面试题(1),面试哪些
|
4天前
|
负载均衡 Go 调度
使用Go语言构建高性能的Web服务器:协程与Channel的深度解析
在追求高性能Web服务的今天,Go语言以其强大的并发性能和简洁的语法赢得了开发者的青睐。本文将深入探讨Go语言在构建高性能Web服务器方面的应用,特别是协程(goroutine)和通道(channel)这两个核心概念。我们将通过示例代码,展示如何利用协程处理并发请求,并通过通道实现协程间的通信和同步,从而构建出高效、稳定的Web服务器。
|
5天前
|
Go 数据处理
Go杂记1-切片Slice作为函数参数那点事儿
Go杂记1-切片Slice作为函数参数那点事儿
7 0
|
5天前
|
存储 人工智能 测试技术
python自动化测试实战 —— CSDN的Web页面自动化测试
python自动化测试实战 —— CSDN的Web页面自动化测试
194 0
|
5天前
|
监控 安全 Shell
记一次应急靶场实战--web1
本次应急靶机题目训练主要是为了应对接下来的护网面试和比赛,顺便提高一下自己对应急和溯源的实战能力,这里有两个逗比的事情发生,一是用D盾分析的时候,电脑环境监测到了,把要分析的马杀了,二是,发现无法使用脚本,在自己本机实验,电脑差点搞崩,还好佬在制作时候只是单次运行会占用.切记不要本机实验,一定要在虚拟机中进行测试.
|
5天前
|
JavaScript 前端开发 索引
【Web 前端】jQuery 里的 each() 是什么函数?你是如何使用它的?
【5月更文挑战第2天】【Web 前端】jQuery 里的 each() 是什么函数?你是如何使用它的?
|
5天前
|
JavaScript 前端开发 C++
【Web 前端】JavaScript window.onload 事件和 jQuery ready 函数有何不同?
【5月更文挑战第2天】【Web 前端】JavaScript window.onload 事件和 jQuery ready 函数有何不同?