goweb编程实战----函数(代码片段)

李元静 李元静     2022-12-01     334

关键词:

目录

前言

本篇博文主要介绍Go语言的函数定义以及其使用方法。

声明与使用函数

在Go语言中,声明函数的格式如下:

func function_name([parameter list])[return_types]
	//函数体

大家在使用编译器进行开发的时候,比如GoLand,就会发现,你输入func回车结构就自动会出现。这也是Go语言开发非常方便的地方。下面,作者来详细说明上面的参数:

  • func:函数声明关键字
  • function_name:函数名
  • parameter:参数列表,可选项,可以没有参数
  • return_types:返回值类型,也是可选项

下面,我们来举例说明使用,示例如下(输出3):

func main() 
	fmt.Println(XaddY(1, 2))

func XaddY(x, y int) int 
	return x + y

返回多个值

在Go语言函数中,如果需要返回多个值,并不需要通过列表或者数组返回,可以单独返回任意多个值。这也是Go语言非常方便的地方,示例如下:

func main() 
	fmt.Println(XaddYOrXmultiplyY(1, 2))

func XaddYOrXmultiplyY(x, y int) (int,int) 
	return x + y, x * y

这里,我们返回了2个参数,一个是加法值,一个是乘法值。

return可以为空

当Go语言函数有返回值的时候,其return可以为空,但并不是实际没有返回值,而是可以将返回值的顺序直接定义在函数定义中。

下面,我们将上面的返回多个值修改一下,示例如下:

func main() 
	fmt.Println(XaddYOrXmultiplyY(1, 2))


func XaddYOrXmultiplyY(x, y int) (a, b int) 
	a = x + y
	b = x * y
	return

这里,返回值的数据依旧与上面返回值一样,因为作者把返回值的返回顺序已经定义到返回参数中,所以return可以为空。

如果你自己写return语句,也可以修改顺序,比如return b,a。它就会先返回b,再返回a。也就是说,它可以根据定义顺序返回,也可以根据你的顺序返回,只要返回参数类型数量是对的,并不会报错。

函数参数

参数

在Go语言中,参数同样分为实参与形参。什么是实参与形参呢?

  • 实参:在调用函数时,传给形参的实际的数据被称为实际参数。
  • 形参:在调用函数时,用于接收外部传入的数据被称为形式参数。

值传递

值传递是指,在调用函数时将实际参数复制一份传递到函数中。这样在函数中进行修改,对传递的参数不会有任何影响。

比如,我们实现一个交换值的函数,看看效果:

func main() 
	var x,y int=5,9
	exchange(x,y)
	fmt.Println(x,y)

func exchange(x, y int)
	var temp int
	temp=x
	x=y
	y=temp

运行之后,你会发现控制台还是5,9,x与y的值没有任何的变化。这就是值传递的结构,不会改变原来的变量值。

引用传递

而引用传递,就会改变原来的变量。同样的,我们还是使用其实现数据的交换,示例如下:

func main() 
	var x, y int = 5, 9
	exchange(&x, &y)
	fmt.Println(x, y)

func exchange(x, y *int) 
	var temp int
	temp = *x
	*x = *y
	*y = temp

这个时候,你再运行,其控制台会输出9,5,因为是引用传递,所以改变了原来的参数值。

可选函数

顾名思义,就是可要可不要,可长可短的参数。定义可选函数的示例如下:

func main() 
	var x = []int2, 3
	fmt.Println(x)

func exchange(arg ...int) 
	var temp int
	temp = arg[0]
	arg[0] = arg[1]
	arg[1] = temp

注意,arg是一个int的切片,它可以直接通过for-range进行遍历。

匿名函数

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

匿名函数的定义

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

//定义
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 := []int1, 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错误时,在程序出现宕机之前被执行,依次来恢复程序。

goweb编程实战----并发goroutine(代码片段)

目录什么是goroutine?使用方式什么是goroutine?在Go语言中,每一个并发执行的活动被称为goroutine。使用go关键字可以创建goroutine,其完整定义如下:gofunc_name()其中,go是关键字,需要放在一个需要调用的函数之前&#... 查看详情

goweb编程实战----并发goroutine(代码片段)

目录什么是goroutine?使用方式什么是goroutine?在Go语言中,每一个并发执行的活动被称为goroutine。使用go关键字可以创建goroutine,其完整定义如下:gofunc_name()其中,go是关键字,需要放在一个需要调用的函数之前&#... 查看详情

goweb编程实战----并发goroutine(代码片段)

目录什么是goroutine?使用方式什么是goroutine?在Go语言中,每一个并发执行的活动被称为goroutine。使用go关键字可以创建goroutine,其完整定义如下:gofunc_name()其中,go是关键字,需要放在一个需要调用的函数之前&#... 查看详情

goweb编程实战----创建客户端(代码片段)

目录创建一个客户端Get()请求Post()请求请求头设置创建一个客户端在Go语言的net/http包中,还提供了一个被称为Client的结构体。该结构体提供了Get()、Post()两个请求函数。下面,我们来分别使用代码实现这些请求。Get()请求... 查看详情

goweb编程实战----反射(代码片段)

目录反射反射的3大原则“接口类型变量”转换为“反射类型对象”“反射类型对象”转换为“接口类型变量”“反射类型对象”修改(值必“可写的”)反射与其他语言一样,Go语言的反射同样是指,计算机程序... 查看详情

goweb编程实战----反射(代码片段)

目录反射反射的3大原则“接口类型变量”转换为“反射类型对象”“反射类型对象”转换为“接口类型变量”“反射类型对象”修改(值必“可写的”)反射与其他语言一样,Go语言的反射同样是指,计算机程序... 查看详情

goweb编程实战----数据类型(代码片段)

...类型、切片类型、Map类型以及结构体类型。布尔型与其他编程语言一样,Go语言的布尔型只可以是tr 查看详情

goweb编程实战----面向对象编程(代码片段)

...有类的概念,但这并不意味着Go语言不支持面向对象编程,毕竟面向对象只是一种编程思想。封装属性其实,学习过C语言都应该清楚,结构体是一个类类的结构,也就是说结构体是类的一种简化形式。 查看详情

goweb编程实战----面向对象编程(代码片段)

...有类的概念,但这并不意味着Go语言不支持面向对象编程,毕竟面向对象只是一种编程思想。封装属性其实,学习过C语言都应该清楚,结构体是一个类类的结构,也就是说结构体是类的一种简化形式。 查看详情

goweb编程实战----流程控制语句(代码片段)

目录流程控制语句if-else语句for循环语句用for循环实现do-while用for循环实现whilebreak指定跳出循环continue语句for-range循环遍历数组遍历字符串遍历map遍历通道(channel)switch-case语句一个分支多个值分支表达式goto语句流程控制... 查看详情

goweb编程实战----流程控制语句(代码片段)

目录流程控制语句if-else语句for循环语句用for循环实现do-while用for循环实现whilebreak指定跳出循环continue语句for-range循环遍历数组遍历字符串遍历map遍历通道(channel)switch-case语句一个分支多个值分支表达式goto语句流程控制... 查看详情

goweb编程实战----创建客户端(代码片段)

目录创建一个客户端Get()请求Post()请求请求头设置创建一个客户端在Go语言的net/http包中,还提供了一个被称为Client的结构体。该结构体提供了Get()、Post()两个请求函数。下面,我们来分别使用代码实现这些请求。Get()请求... 查看详情

goweb编程实战----创建客户端(代码片段)

目录创建一个客户端Get()请求Post()请求请求头设置创建一个客户端在Go语言的net/http包中,还提供了一个被称为Client的结构体。该结构体提供了Get()、Post()两个请求函数。下面,我们来分别使用代码实现这些请求。Get()请求... 查看详情

goweb编程实战----go语言的基础语法(代码片段)

目录前言HelloWorld包的声明与导入运行程序方式基础语法注释标识符变量常量运算符前言很高兴能够一起和大家学习Go语言,对于它的场景其实很多,包括云计算、容器虚拟化、分布式存储、网络爬虫、运维开发、Web开发... 查看详情

goweb编程实战----go语言的基础语法(代码片段)

目录前言HelloWorld包的声明与导入运行程序方式基础语法注释标识符变量常量运算符前言很高兴能够一起和大家学习Go语言,对于它的场景其实很多,包括云计算、容器虚拟化、分布式存储、网络爬虫、运维开发、Web开发... 查看详情

goweb编程实战----并发goroutine(代码片段)

目录什么是goroutine?使用方式什么是goroutine?在Go语言中,每一个并发执行的活动被称为goroutine。使用go关键字可以创建goroutine,其完整定义如下:gofunc_name()其中,go是关键字,需要放在一个需要调用的函数之前&#... 查看详情

goweb编程实战----创建http与https服务器端(代码片段)

目录创建一个HTTP服务端ListenAndServe()ServeHTTP()方法的使用示例定义Refer结构体实现ServeHTTP()方法创建一个HTTPS服务端创建证书与私钥创建HTTPS服务端创建一个HTTP服务端其实Go语言创建一个简单的HTTP服务器程序,与JavaWeb的servlet差... 查看详情

goweb编程实战----面向对象编程(代码片段)

...有类的概念,但这并不意味着Go语言不支持面向对象编程,毕竟面向对象只是一种编程思想。封装属性其实,学习过C语言都应该清楚,结构体是一个类类的结构,也就是说结构体是类的一种简化形式。所以ÿ... 查看详情