go语言中的函数 - Go语言中文社区

go语言中的函数


1、函数的定义以及语法

根据下面代码初步了解go中的函数以及其语法 :

//函数:为完成某一功能的程序指令(语句)的集合。
//为什么使用函数:1)代码复用;2)方便维护;3)模块化
//golang中函数的基本语法:
/*	func 函数名(形参列表)(返回值列表){
	执行语句...
	return 返回值列表
}*/
//注意再golang中可以有多个返回值可方便了
//注意:返回值只用指定返回类型即可
func Cal(n1 float64, n2 float64, operator byte) (float64, byte, float64, float64) {
	var res float64
	switch operator {
	case '+':
		res = n1 + n2
	case '-':
		res = n1 - n2
	case '*':
		res = n1 * n2
	case '/':
		res = n1 / n2
	default:
		fmt.Println("运算符出错")
	}
	return n1, operator, n2, res
}


func main() {
	//调用函数  接收多个返回值
	var n1, operator, n2, res = cal(12, 12, '+')
	fmt.Printf("%f%c%f=%f n", n1, operator, n2, &res)
	//当有多个返回值时 只想取其中的某一个其它返回值可用 _表示占位忽略
	_, _, _, res = utils.Cal(12, 12, '+')
	 fmt.Println(res)
	 }

2、go中函数的特性

2.1、go中的函数参数和返回值都可以有多个,当只想接收多个返回值中的一部分时,不需要接收的使用 _表示占位忽略;

2.1、go中的函数命名时必须以字母开头,当以小写字母开头时只能在本包访问,当以大写字母开头时,可以在包外访问;

2.3、当需要在函数中修改函数外的变量时需要将需要修改的变量的地址传入函数中,通过地址操作变量

2.4、go中不支持函数重载,即函数名相同为参数不同是不允许的

2.5、go中,函数也是一种数据类型,可以将函数赋值给一个变量,然后通过变量调用函数,如下所示:

func main(){
    //将函数赋给变量
 	a := getSum
	fmt.Printf("%T,%T", a, getSum)
	res1 := a(10, 20)
	fmt.Println("和:", res1)
}

func getSum(n1 int, n2 int) int {
	return n1 + n2
}

结果:
在这里插入图片描述
2.6、函数既然是一种数据类型并且赋值给变量,则函数就也可以作为函数的形参内传递、调用

2.7、在go中为了简化数据类型订定义,支持自定义数据类型,
基本语法: type 自定义数据类型 数据类型 //相当于一个别名
例:type myInt int //此时muInt就等价 int 来使用了
例:

func main(){
//将函数作为形参
	res2 := getSum1(getSum, 12, 12)
	fmt.Println(res2)
	}
//两数相加
func getSum(n1 int, n2 int) int {
	return n1 + n2
}

//也可以将函数自定义成为一个数据类型
type myFuncType func(int, int) int
//将函数类型的变量做参数
func getSum1(funvar myFuncType, n1 int, n2 int) int {
   //通过变量调用函数
	return funvar(n1, n2)
}

2.8、go支持可变形参
基本语法: func 函数名 (args… 参数类型) 返回值类型{

}
2.8.1、args是slice切片,同过args[index]可以访问到各个值
2.8.2、若一个函数的参数列表中有可变参数,则需要将可变参数放在形参列表最后
例:

//可变参数的函数 args是slice切片
func getSumByArgs(args ...int) int {
	var res int
	for i := 0; i < len(args); i++ {
		res += args[i]
	}
	return res
}
func main(){
	//调用有可变参数的函数
	resArgs := getSumByArgs(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)
	fmt.Println("利用函数的可变参数求和sum:", resArgs)
}

3、init函数

在go语言中每一个源文件都包含一个init函数,该函数会在main函数执行前,被go框架调用,也就是说init会在main函数前被调用
注意:1)该函数由go框架调用
2)如果一个文件中含有全局变量时,全局变量会比init函数先执行,
3)init()主要用于完成一些初始化的工作
4)如果在一个main.go文件中导入了utils.go, 则在执行main.go时会先执行utils.go中的init()

func init(){
    fmt.Println("init()...")
}
func main(){
    fmt.Println("main()...")
}

结果:可见init()在没有被动调用时优于main()先执行
在这里插入图片描述

4、匿名函数(不得不说挺别致的 )

go语言支持匿名函数,匿名函数就是没有名字的函数,如果某个函数只希望使用一次,就可以考虑使用匿名函数 (那还定义函数干嘛呢?!存在即合理,它还是有应用场景的,比如接下来要说的闭包),匿名函数也可以实现多次调用。

匿名函数有三种实现方式,如下:

//3、全局匿名函数 :将匿名函数赋给全局变量
var varFunc1 = func(n1 int, n2 int) int {
	return n1 + n2
}

func main() {
	//1、在定义匿名函数是就直接调用,这种方式匿名函数只能调用一次
	res := func(n1 int, n2 int) int {
		return n1 + n2
	}(12, 12)
	fmt.Println("调用匿名函数求和:", res)

	//2、将匿名函数赋给一个变量,在通过变量来调用匿名函数,可通过变量多次调用
	varFunc := func(n1 int, n2 int) int {
		return n1 + n2
	}
	fmt.Println("通过变量调用匿名函数求和:", varFunc(12, 12))

	fmt.Println("通过全局变量调用匿名函数求和:", varFunc1(12, 12))
}

5、闭包

闭包就是一个函数和与其相关的应用环境组合的一个整体(实体)
5.1、下面结合例子分析:

//2、闭包
//闭包就是一个函数和与其相关的应用环境组成的一个整体(实体)
//定义一个名为Addupper的函数 其返回的数据类型为 func(int) int
//而Addupper()返回的是一个匿名函数 ,而这个匿名函数又引用到Addupper中的变量n,
//因此这个匿名函数就和n形成一个整体构成闭包。
func Addupper() func(int) int {
	var n int = 10
	return func(x int) int {
		n = n + x
		return n
	}
}
func main(){
	//2.1、调用Addupper函数
	f := Addupper()
	fmt.Println(f(1))
	fmt.Println(f(2))
	fmt.Println(f(3))
}
//可以将闭包看作一个类,函数是操作,n是字段,函数的它使用的变量n构成闭包
//注意:是Addupper中的匿名函数和匿名函数引用的变量n构成了闭包
func Addupper1() func(int) int {
	var n int = 10
	var str = "hello"
	return func(x int) int {
		n = n + x
		str += " world! "
		fmt.Println("str=", str)
		return n
	}
}
func main(){
	//2.1、调用Addupper函数
	f := Addupper1()
	fmt.Println(f(1))
	fmt.Println(f(2))
	fmt.Println(f(3))
}

结果:
我突然发现c 在多次调用中 n和str的保存到了上一次值的变化 ,也就是说,当使用将行数赋给变量后,函数内部的变量的变化可以被保存起来同时可以通过 函数中的匿名函数来操作函数中的变量,这像极了爱情,不,这像极了类和对象,对象中的字段保存数据,通过方法又可以操作数据
在这里插入图片描述

6、函数的defer(延时机制)

在函数中,程序员经常需要创建资源,为了在函数执行完毕后,即使释放资源,Go的设计者提供了defer延时机制。
注意:defer后面只能一个函数调用语句
6.1、结合下面例子分析:

func main(){
//2、函数的defer(延时机制)
	//在函数中,程序员经常需要创建资源,为了在函数执行完毕后,即使释放资源,Go的设计者提供了defer延时机制
	//定义匿名函数并赋给变量
	funcDefer := func(n1 int, n2 int) int {
		defer fmt.Println("ok1 n1=", n1)
		defer fmt.Println("ok2 n2=", n2)

		res := n1 + n2
		defer fmt.Println("ok3 res=", res)
		return res
	}

	varDefer := funcDefer(12, 12)
	fmt.Println("sun:", varDefer)

结果:
在这里插入图片描述
分析:1)当go执行到一个defer时,不会立即执行defer后的函数调用,而是将defer后的语句压入到一个栈中(defer栈),然后继续执行下一条语句
2)当defer所处的函数执行完毕,再从defer栈中,依次从栈顶取出语句执行
3)defer 的应用场景 当函数执行完,及时释放函数创建的资源 如管关闭文件资源
在这里插入图片描述

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_44373940/article/details/104410238
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢